From 0b2a587b69524dafde97f76bad27721afebdcddb Mon Sep 17 00:00:00 2001 From: liuhaoran Date: Tue, 16 Jun 2026 19:30:44 +0800 Subject: [PATCH] school_gengxin (#2) Co-authored-by: hrrr Reviewed-on: https://git.pengyuthon.cn/pengyuthon/shcool/pulls/2 --- learning_center/__manifest__.py | 2 +- learning_center/models/__init__.py | 2 +- .../__pycache__/__init__.cpython-312.pyc | Bin 578 -> 543 bytes .../course_homework.cpython-312.pyc | Bin 10263 -> 14111 bytes .../course_homework_submit.cpython-312.pyc | Bin 5826 -> 7134 bytes .../course_teaching_class.cpython-312.pyc | Bin 16823 -> 16823 bytes learning_center/models/course_homework.py | 233 ++++++++++++------ .../models/course_homework_submit.py | 27 ++ .../models/course_teaching_class.py | 5 +- learning_center/models/teach_class.py | 3 +- learning_center/security/ir.model.access.csv | 2 - .../views/view_course_teaching_class.xml | 9 +- .../__pycache__/student_info.cpython-312.pyc | Bin 4195 -> 6101 bytes student_organization/models/student_info.py | 54 +++- .../views/view_student_info.xml | 2 +- 15 files changed, 256 insertions(+), 83 deletions(-) diff --git a/learning_center/__manifest__.py b/learning_center/__manifest__.py index 22aa1ac..afb027e 100644 --- a/learning_center/__manifest__.py +++ b/learning_center/__manifest__.py @@ -25,7 +25,7 @@ 'views/view_course_teaching_class.xml', 'views/view_course_student_score.xml', 'views/view_course_homework_student.xml', - 'views/view_teach_class.xml', + # 'views/view_teach_class.xml', ], diff --git a/learning_center/models/__init__.py b/learning_center/models/__init__.py index 043df1a..1245d4b 100644 --- a/learning_center/models/__init__.py +++ b/learning_center/models/__init__.py @@ -7,4 +7,4 @@ from . import course_homework_submit from . import course_score_item from . import course_student_score from . import course_teaching_class -from . import teach_class \ No newline at end of file +# from . import teach_class \ No newline at end of file diff --git a/learning_center/models/__pycache__/__init__.cpython-312.pyc b/learning_center/models/__pycache__/__init__.cpython-312.pyc index 69332b436027af9564e8fe9011a8d16bdd33c31b..d1f1900da224c398a2495a2064770d544b139bce 100644 GIT binary patch delta 70 zcmX@aGM|O_G%qg~0}wRqG|2Lu$ScWMFj2jbrIJgNd*X`I%zm0&lUo_}C+}no;SvC< VVg%x1g~{Sf3LN(sl#BR)TmW|e5C#AM delta 103 zcmbQwa)^cZG%qg~0}xE=)64Rn$ScWMGf}-zAcY}?D~BPMD~gMep^{sZXX2dGLYj=X zxJyzKlQZIza}tY-{WQ5JXEEwC74b}-#u&~e2sDEch>Mjce`i$SzRRF|k3q7CA1DF< DX!#k; diff --git a/learning_center/models/__pycache__/course_homework.cpython-312.pyc b/learning_center/models/__pycache__/course_homework.cpython-312.pyc index dce2bc4cfd6b04883fc42d398a8a8f42bc2109c7..d43fdd7c0307165e30aa081eaf9153931b75d0f6 100644 GIT binary patch literal 14111 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 Z`DZHsZ@R5Ix)4~}GT8EW3d@AZ{{Wly%K`uZ delta 4453 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 diff --git a/learning_center/models/__pycache__/course_homework_submit.cpython-312.pyc b/learning_center/models/__pycache__/course_homework_submit.cpython-312.pyc index 076fe2ed0cfbecd92dee6758084ad9bb2ab020f3..bef74ceb1be007c9e93a9f048f1f40766492ac51 100644 GIT binary patch delta 1829 zcmZ`(eQZ-z6ujAHnzzI^RW*G42D?w+6OZNF~MjUVpIAaW1}DBzE)(G zw8R+-!QglbBO!q(CLs6+Sz?SB{}5wh{Kq=Y=98e2ZOC6%0i*t-=e({srrxCIo{!(T z_uXI5IiED&Xm@|%aybaBqo219+$bA%pAa1)A&0NL?HA-eqON+2s_p9P%a0kK33UtB zsE=O`T;dQ+!gIl zB<*n4^qF_3kH0?o;d$elV;x;E$~zZR??MRZJc!!bTIPqH)fxeL32im{pET~3o=%5n_=6ZB_*wY7(*xp7dWs}qFRUYcio6E@MT%ac z1`m~^) zfFOLZ4-Pej7ef)UN(PHMQ|_*z;q;hF!XG@q3N@&P9Bc#DZ=L7BsZ@Lx=H zlAT^c4)W>$A%*{klw&@@B8IJlvlX7Lhs_lCv;Ks}Hljc}@d zyZG)+U=CJv#FI?ddg4)Sf85w2+jm-Lg%FQL0u)?#dyn)TiH>xRxgW{$-+BGnjtRMR zTyD(CjTbt;kz4aTdAR%s&%CVT-(29G78gH)a*7x?Y-MSc?rnzxqX)PIhOCvM14!GP zRebls2a&cpFfi{U`4p#fDV{BZ6S0rxER|2xSW^Q11M-|G`aH&8az$Dd&de&s1Ka^l z5tAz+e(UPl$qzEnnp4M5-a7jJbmq`h_Wbn8_iksd{`B$i&mSEt)X>z4V-}H9uU@(J z#syXdnOhk)Ww9sgP?xO!G=*L9c*Jzh6zlH(i1xhcE*5t@me67ehW{2ridX}RM=`xn z>#P%WQ`!^KgP3YMQ41H+ilsg?EwDlcmqMxg(^dx+@0is1Rkn?lt;{;Vb$W+io`5X5DkoP> z%&)&*v*>L4bb7pId9G&pSWVk6B46#kM|ii(17%ZQXH|^SZVW$klQtO1d9S3|W_*rk z78$WnR5OL1L^Q&-K#U=EtPN2m;dnF(?3ngG7E(19>{qQ}XWF-E5iOkPkH-oOmuv)v zwNQ-JV{R>qMik8`teJ-c&J?5ZO{x}QI1&nsBV(p(W^{zLNF*3kXrY~Ol&vp}kP^hB zz*cdw&f+_@t delta 579 zcmca-en^+^G%qg~0}#~9>Sc)tPvo1#e2Rr(<5F=Jo)ohb^K_;ZixkT>R+CS#D9c)> z*sQT#%>+`-z!0UAV%NeDrJG_8B=u4pCUdaLvpX(gOmRwao~*~JF6)va15=yg+QP6J zqKzTSu+mM_ee(v^5Z1{G+;)sIo8!6F7=;yq(#6a`LP0^HNE}EP$xoiaqs6E{`7qBB zM%l?7y!njglYj7L2+IH^-87ksR6&X~K!oPxVm@a^>&@HwelqIl0!3a1fQ0oxEH@BK zAH=c&u?#?jA&_v>WGOP9d`G~Q%?QY=(wsb(M~)}GC^029J}0#-HOFIepx{hqKTV^_ z)nbns)h5S_H`m|dE-p>V%`Aye%gjl=#gD|vOUzBZ#o|$tn{$f~Dx933SCX1nQltd3 z(HKbFVo%P`%>@eG;so1M6rY&_cKJ17cc(2#}*!G89RG*x=A&2eCi|C=8320V8Si3JGN<=^GqMH#p=!urkZBePCnY z7hk~rg`JsKx54!T$K(f6$*dol_*u0lXG!Zx7sY{$fSdS>!zMRBr8Fnit|)Qx25Cvr UP)0`W8D{fsX4-sZ0I|VJ0Z*@#761SM diff --git a/learning_center/models/__pycache__/course_teaching_class.cpython-312.pyc b/learning_center/models/__pycache__/course_teaching_class.cpython-312.pyc index 08725f7ed075ec4d240b1bf1d07e20d9cd57af07..4ff25bb9644f9b954896a4155a29a001aded9544 100644 GIT binary patch delta 24 ecmdnq%(%Uok@qw&FBbz4yxVG!RlAXQl_LOOv now: + record.is_submit_open = True + else: + record.is_submit_open = False + + # ====================== 统计提交人数 ====================== def _compute_submit_stats(self): for record in self: - # 按教学班 + 选课状态筛选学生 domain = [('state', '=', 'enrolled')] if record.teaching_class_id: - # 优先按当前作业所属教学班统计(核心修正) domain.append(('teaching_class_id', '=', record.teaching_class_id.id)) else: - # 无教学班时,回退到整门课程统计 domain.append(('course_id', '=', record.course_id.id)) enrollments = self.env['course.teaching_class.enrollment'].search(domain) student_ids = enrollments.mapped('student_id') record.total_students = len(student_ids) - # 该作业所有提交记录 base_domain = [('homework_id', '=', record.id)] all_submit = self.env['course.homework.submit'].search(base_domain) - total_submit = len(all_submit) - deadline_val = record.deadline - if deadline_val: - # 按时提交 - on_time_submit = all_submit.filtered(lambda s: s.submit_time and s.submit_time <= deadline_val) - # 逾期提交 - late_submit = all_submit.filtered(lambda s: s.submit_time and s.submit_time > deadline_val) - record.submitted_count = len(on_time_submit) - record.late_count = len(late_submit) - else: - record.submitted_count = total_submit - record.late_count = 0 + # 已提交 = 状态submitted/graded + submit_ok = all_submit.filtered(lambda s: s.state in ['submitted', 'graded']) + late_submit = submit_ok.filtered(lambda s: s.is_late) - # 未提交 = 班级总人数 - 所有提交人数 - record.unsubmitted_count = record.total_students - total_submit + record.submitted_count = len(submit_ok) + record.late_count = len(late_submit) + # 未提交 = 总人数 - 已提交人数 + record.unsubmitted_count = record.total_students - len(submit_ok) + # ====================== 发布作业(核心逻辑修正) ====================== def action_publish(self): + self.ensure_one() + if self.state == 'published': + return self.state = 'published' self.publish_time = fields.Datetime.now() + # 1. 批量为本班学生生成空白未提交记录 + self._auto_create_empty_submit() + # 2. 推送作业通知给学生 + self._send_homework_notice_to_students() + def _send_homework_notice_to_students(self): + """发布作业后推送消息给教学班学生""" + self.ensure_one() + if not self.teaching_class_id: + return + # 获取当前教学班所有已选课学生 + enrolls = self.env['course.teaching_class.enrollment'].search([ + ('teaching_class_id', '=', self.teaching_class_id.id), + ('state', '=', 'enrolled') + ]) + student_users = enrolls.mapped('student_id.user_id').filtered(lambda u: u) + if not student_users: + return + # 消息内容 + subject = f"新作业发布:{self.name}" + body = f""" +

课程:{self.course_id.name}

+

作业名称:{self.name}

+

截止时间:{self.deadline or '无'}

+

作业要求:{self.requirement or '无'}

+ """ + # 发送消息(关联当前作业记录,学生在消息中心可直接跳转) + self.message_post( + subject=subject, + body=body, + partner_ids=student_users.mapped('partner_id').ids, + subtype_xmlid='mail.mt_comment' + ) + + def _auto_create_empty_submit(self): + """仅发布时执行:自动给教学班所有已选课学生生成空白未提交记录""" + self.ensure_one() + if not self.teaching_class_id: + return + # 获取当前教学班已注册学生 + enroll_records = self.env['course.teaching_class.enrollment'].search([ + ('teaching_class_id', '=', self.teaching_class_id.id), + ('state', '=', 'enrolled') + ]) + student_ids = enroll_records.mapped('student_id').ids + if not student_ids: + return + + # 过滤掉已经存在提交记录的学生,避免重复生成 + exist_student_ids = self.submit_ids.mapped('student_id').ids + need_create_stu = [sid for sid in student_ids if sid not in exist_student_ids] + if not need_create_stu: + return + + submit_model = self.env['course.homework.submit'] + batch_vals = [] + for stu_id in need_create_stu: + batch_vals.append({ + 'homework_id': self.id, + 'student_id': stu_id, + 'state': 'unsubmit' # 默认未提交 + }) + # 批量创建空白提交记录 + submit_model.create(batch_vals) + + # ====================== 草稿/关闭作业 ====================== def action_draft(self): self.state = 'draft' def action_close(self): self.state = 'closed' + # 关闭作业强制关闭提交通道 self.is_submit_open = False + # ====================== 时间校验约束 ====================== @api.constrains('deadline', 'late_deadline') def _check_deadline(self): for record in self: if record.late_deadline and record.late_deadline < record.deadline: raise ValidationError('补交截止时间必须晚于提交截止时间') + # ====================== 学生提交相关计算字段 ====================== def _get_current_student(self): """获取当前登录的学生""" student = self.env['student.info'].search([('user_id', '=', self.env.uid)], limit=1) @@ -103,7 +177,7 @@ class CourseHomework(models.Model): my_submit_filename = fields.Char(string='文件名', compute='_compute_my_submit') my_submit_content = fields.Html(string='提交内容', compute='_compute_my_submit') - # 提交状态(用于前端显示) + # 前端展示提交状态 submit_state = fields.Selection([ ('not_submitted', '未提交'), ('submitted', '已提交'), @@ -111,69 +185,88 @@ class CourseHomework(models.Model): ('late', '逾期提交'), ], string='提交状态', compute='_compute_my_submit') - # 是否可以提交 + # 是否可以提交:严格依赖提交通道开启状态 can_submit = fields.Boolean(string='可以提交', compute='_compute_can_submit') - @api.depends('submit_ids') + @api.depends('submit_ids', 'submit_ids.student_id', 'submit_ids.state', 'submit_ids.is_late') def _compute_my_submit(self): + student = self._get_current_student() for record in self: - student = self._get_current_student() - if student: - submit = record.submit_ids.filtered(lambda s: s.student_id == student) - if submit: - record.my_submit_id = submit.id - record.my_submit_state = submit.state - record.my_submit_time = submit.submit_time - record.my_score = submit.score - record.my_grade_level = submit.grade_level - record.my_comment = submit.comment - record.my_submit_file = submit.submit_file - record.my_submit_filename = submit.submit_filename - record.my_submit_content = submit.submit_content - - # 计算提交状态 - if submit.state == 'graded': - record.submit_state = 'graded' - elif submit.is_late: - record.submit_state = 'late' - else: - record.submit_state = 'submitted' - else: - record.submit_state = 'not_submitted' - else: + if not student: + record.my_submit_id = False record.submit_state = 'not_submitted' + continue + submit = record.submit_ids.filtered(lambda s: s.student_id == student) + if not submit: + record.my_submit_id = False + record.submit_state = 'not_submitted' + continue + submit = submit[0] + record.my_submit_id = submit.id + record.my_submit_time = submit.submit_time + record.my_score = submit.score + record.my_grade_level = submit.grade_level + record.my_comment = submit.comment + record.my_submit_file = submit.submit_file + record.my_submit_filename = submit.submit_filename + record.my_submit_content = submit.submit_content + # 适配前端状态展示 + if submit.state == 'unsubmit': + record.submit_state = 'not_submitted' + elif submit.state == 'graded': + record.submit_state = 'graded' + elif submit.is_late: + record.submit_state = 'late' + else: + record.submit_state = 'submitted' + + @api.depends('state', 'is_submit_open', 'my_submit_state') def _compute_can_submit(self): for record in self: - # 作业已发布、提交通道开启、未截止、且未提交 - can = (record.state == 'published' and - record.is_submit_open and - record.deadline and - record.deadline > fields.Datetime.now() and - record.my_submit_state != 'submitted' and - record.my_submit_state != 'graded') + # 核心条件:提交通道必须开启,且未提交/未批改 + can = False + if record.is_submit_open and record.my_submit_state not in ['submitted', 'graded']: + can = True record.can_submit = can + # ====================== 提交作业按钮方法 ====================== def action_submit_homework(self): - """学生提交作业""" self.ensure_one() student = self._get_current_student() if not student: raise ValidationError('请先关联学生信息') - # 检查提交权限 + # 核心校验:通道关闭直接报错,禁止进入提交弹窗 if not self.can_submit: - raise ValidationError('当前无法提交作业') + raise ValidationError('当前提交通道已关闭,无法提交作业') - # 打开提交表单 - return { - 'type': 'ir.actions.act_window', - 'name': '提交作业', - 'res_model': 'course.homework.submit', - 'view_mode': 'form', - 'target': 'new', - 'context': { - 'default_homework_id': self.id, - 'default_student_id': student.id, - }, - } \ No newline at end of file + # 后续打开提交表单逻辑不变 + exist_submit = self.env['course.homework.submit'].search([ + ('homework_id', '=', self.id), + ('student_id', '=', student.id) + ], limit=1) + if exist_submit: + return { + 'type': 'ir.actions.act_window', + 'name': '提交作业', + 'res_model': 'course.homework.submit', + 'res_id': exist_submit.id, + 'view_mode': 'form', + 'target': 'new', + } + else: + return { + 'type': 'ir.actions.act_window', + 'name': '提交作业', + 'res_model': 'course.homework.submit', + 'view_mode': 'form', + 'target': 'new', + 'context': {'default_homework_id': self.id, 'default_student_id': student.id}, + } + + # 移除原create里自动生成空白提交的代码,草稿不生成 + def create(self, vals): + homework_record = super().create(vals) + # 草稿状态不执行自动生成提交记录,移到action_publish + return homework_record \ No newline at end of file diff --git a/learning_center/models/course_homework_submit.py b/learning_center/models/course_homework_submit.py index 681e245..37a89a3 100644 --- a/learning_center/models/course_homework_submit.py +++ b/learning_center/models/course_homework_submit.py @@ -38,6 +38,7 @@ class CourseHomeworkSubmit(models.Model): grader_id = fields.Many2one('res.users', string='批改人') grade_time = fields.Datetime(string='批改时间') state = fields.Selection([ + ('unsubmit', '未提交'), ('submitted', '已提交'), ('graded', '已批改'), ], string='状态', default='submitted') @@ -87,6 +88,32 @@ class CourseHomeworkSubmit(models.Model): else: record.grade_level = False + @api.model + def create(self, vals): + submit_rec = super().create(vals) + self._check_submit_change_state(submit_rec) + return submit_rec + + def write(self, vals): + res = super().write(vals) + for rec in self: + self._check_submit_change_state(rec) + return res + + def _check_submit_change_state(self, submit_rec): + """统一提取状态判断逻辑,create和write共用""" + # 仅空白未提交状态才自动切换 + if submit_rec.state != 'unsubmit': + return + # 判断:有提交文件 或者 填写了提交内容 = 完成提交 + has_file = bool(submit_rec.submit_file) + has_content = bool(submit_rec.submit_content) + if has_file or has_content: + submit_rec.write({ + 'state': 'submitted', + 'submit_time': fields.Datetime.now() + }) + # class CourseHomeworkSubmitBatchGrade(models.TransientModel): # _name = 'course.homework.submit.batch.grade' # _description = '作业批量批改向导' diff --git a/learning_center/models/course_teaching_class.py b/learning_center/models/course_teaching_class.py index 515af67..7c249cc 100644 --- a/learning_center/models/course_teaching_class.py +++ b/learning_center/models/course_teaching_class.py @@ -288,4 +288,7 @@ class CourseTeachingClassEnrollmentWizard(models.TransientModel): if create_list: self.env['course.teaching_class.enrollment'].create(create_list) - return {'type': 'ir.actions.act_window_close'} \ No newline at end of file + return {'type': 'ir.actions.act_window_close'} + + + diff --git a/learning_center/models/teach_class.py b/learning_center/models/teach_class.py index 454f957..384b170 100644 --- a/learning_center/models/teach_class.py +++ b/learning_center/models/teach_class.py @@ -10,4 +10,5 @@ class TeachClass(models.Model): stu_name=fields.Char(related='student_id.stu_name',string='姓名') stu_sex = fields.Selection(related='student_id.stu_sex', string="性别") stu_phone = fields.Char(related='student_id.stu_phone', string="手机号") - stu_grade_xx = fields.Many2one(related='student_id.stu_grade_xx', string="年级") \ No newline at end of file + stu_grade_xx = fields.Many2one(related='student_id.stu_grade_xx', string="年级") + diff --git a/learning_center/security/ir.model.access.csv b/learning_center/security/ir.model.access.csv index 41f39ec..f137695 100644 --- a/learning_center/security/ir.model.access.csv +++ b/learning_center/security/ir.model.access.csv @@ -11,8 +11,6 @@ access_course_syllabus_sys,course.syllabus.access.sys,model_course_syllabus,base access_course_teaching_class_sys,course.teaching.class.access.sys,model_course_teaching_class,base.group_system,1,1,1,1 access_course_teaching_class_enrollment_sys,course.teaching.class.enrollment.access.sys,model_course_teaching_class_enrollment,base.group_system,1,1,1,1 access_course_teaching_class_enrollment_wizard_sys,course.teaching.class.enrollment.access.sys,model_course_teaching_class_enrollment_wizard,base.group_system,1,1,1,1 -access_teach_class_teacher,teach.class.access.teacher,model_teach_class,edu_base.group_teacher,1,1,0,0 -access_teach_class_sys,teach.class.access.sys,model_teach_class,base.group_system,1,1,1,1 access_course_teaching_class_teacher,course.teaching.class.access.teacher,model_course_teaching_class,edu_base.group_teacher,1,0,0,0 access_course_teaching_class_enrollment_teacher,course.teaching.class.enrollment.access.teacher,model_course_teaching_class_enrollment,edu_base.group_teacher,1,0,0,0 access_course_homework_teacher,course.homework.access.teacher,model_course_homework,edu_base.group_teacher,1,1,1,0 diff --git a/learning_center/views/view_course_teaching_class.xml b/learning_center/views/view_course_teaching_class.xml index 772069e..b9b89b3 100644 --- a/learning_center/views/view_course_teaching_class.xml +++ b/learning_center/views/view_course_teaching_class.xml @@ -204,9 +204,14 @@ + + 我的班级 + + + - 教学班管理 - + 我的班级 + 15 diff --git a/student_organization/models/__pycache__/student_info.cpython-312.pyc b/student_organization/models/__pycache__/student_info.cpython-312.pyc index e7fb7d16d3fcc72d4f371773a8f6f87053689335..bf9112bccc43bb8cef8f45e285ec774d4ceb93d3 100644 GIT binary patch delta 2798 zcma)8e@q+K9e?NZo$veuCx-CTPEGh}AP`s}DWPfBwKQED(kRmgPNkdccMucfL+|V+ zrDi5;+L&z>M%Rp>rovgah7Hmt%BG-@O8s-%G|9-Fa8B*Y)ESb$N=7GD{bSmDcZPsO zr9DgUzCS+SAMg9#`#yi^{(Dp2Uu`xsz@yyN-0v(H&nw>Fg}Dg;0i=RpfbvoU2Crd& z_R-H^0G2lbVa@g)r*OuKoz1WX)8Cs}Ps^Rd?#I|x!S|xd3KzDsK%& zzq}cz({a#C!S7$-HgKLeI7fNwP6E#}s^w%j0>x1Hg;1~ZU*l=cf^9rB;*}6{sENmn z$^=4CJcr26MMxEwZ;mfdjOpa9QA~OahyamI$uM%^4uT{6^5`#@uiVX!-SJS^osaFN zc;zlzVbQR8#K5dPU`MH43Nl@zoJt{gxJJ{FNGc1Z0bd~WkgPKoK;@9=gHkB?x*~F8 z4mZ)@Oz{WV$YfSnz77Xz<_jph(#iKxHOhy4wH~mRAZnB^_@NgyiyFea@boQ@M7c2{ zi%5<*Fu!tper0}YWpY0I@udfU`~c@q;>uwZ@P{`Nk#I?ZVpvrA%%3+kU@O%SfGQ`U zK4H)oK8515|0fJ#VYCvmI z(4RZWThKH~wBNK@rqj>}nW&+c?xP?(YtlSo#jr7Il>fH9uYQu@))51cgZ!*{!<_lQ zO#!rQv1Fr+YzdR&sSRjdzXCs}qU;up?Xf2I9W}~ZhYXvdCK<2uJpk?R8!)$hO?TvK zibF>Y`1f77osV(Q0rR6Vw%?jdc+)4!Y$xs0i(PPq9p<*L64W=#zR6XNjB*8kZcn4pDD7E2$kMg)P6n3d5IUEr}kpUGT4+g7DQ0fbW zRO%_T8?(6KGQq$=AUtG$)hCOMeMpK73gjMjVwD5=0FMHmq_ zfw6zmdLpD}>DMm%_FF3-e~9OYZ%(hgJG~sgvoe3dy~%|5cdy*LoBi#rukQV7c_O)d z`%*UkUUvTO<{SIfz4HVU!1Qb>GAS|y5+i|Aoh zV+d%e&I^RXA`1C} zf)-x2<@Q8pQ9H5ZwRDIl)w-?@gnA{F7X*J0uSO7LaxdK*V?=LtM*%*6LynUhFO1Zv zr%Bw(UATFDGXhpwkY6-WJ6?PF$>ghPhiB2zwBTq;JDTIBOnyNMd`$d%+ zJCrVcBUSJQ&d*gob#(G*@>JT{oZ#;lxib}YNzZh9%H5WD;j!9#(~)-W&$ucx?wX9N zI)kmcW0T#PgiQs@l^TCkL;Ywk>FPg zfYUv7aPnaC#f7qci)9BE$_~u&>9S`MS{Vv5yQ`q%Tk>FYIy2ZP7uh66O?~j_L|WlTyE_UC@t15Ga?;8+gat;)@zn#!ZnepL3!5J z+D#rMMBW+I1jRuy1Z7l3IA%b?Zyq{IXj^XM{bDdE2>5+Jfu%BejE?9#&tVdgi6M%! z_!fL~`wzAr$~0H}=jKm$9#dHRUt%nz)J_OA)0J(pUlihe)r74Q~ d0_<4;dp-yCU$X*5ITO_r4dV^}0fg2({11l_=)eE~ delta 902 zcmYjPT}V?=96#rN&rL}5CM>+xr*95Tj<|W5fAX(v6r}`A45Nb#KMwo2!s-pu%5Koy#c6im@iMlB3-UwC% z+aEtc+BlzhiYiW%sG!PG)I)JEnGl$|kE;9sQ@1g-d1kMi^JLoxg%y3_FFU_E9AR4991YW#rYJ{?_vkVIksc< zd8t}1+Hk8tp~hh*#4d76%6RLUj)|*G%*qAm zA^Y+=Y$lJC(FW^|nN0~9$?5qNIaG>`tu(=AVjh=meC+7-GH%KZX{<8d%45 zWXCZJLu9NbYBLX5Z2K!%*3qhVHqn@6T%;MuA4baswz)5MYz)@KZi zG8`p=0QS)j4w7+KuqjGmW{iequ;*>QfB94Wv10x~ewXB3JuW9W?#F(58Pht*@5Vv5 zsbsRbsnm2*H)RXulH`Ir<~1FRrRR*4ZbO~!n;>QPy0eS*(pU(SanC?6PoXIzJ*}ru z1_vp72CN?TR5DYtz;u~Qbl?{sJQI-LZs;R@-nV%LNDa$3?@g{uuC;E9C-*r?j2!Sl z3RuW4#OyImG6e$}24;mYdyiP8!4$6>NKaTTaExWyepc^8Wh7~!TtXkkH)xJMtqi;T c!9xhYfZ%%&{OJ+;VPq{_?k;uz0u);AKLjV$=Kufz diff --git a/student_organization/models/student_info.py b/student_organization/models/student_info.py index ca54486..b7b06ca 100644 --- a/student_organization/models/student_info.py +++ b/student_organization/models/student_info.py @@ -1,4 +1,6 @@ from odoo import api,models,fields +from odoo.exceptions import ValidationError + class StudentInfo(models.Model): _name="student.info" @@ -24,7 +26,7 @@ class StudentInfo(models.Model): 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_grade_bx=fields.Many2one('basic.grade.xx',string='年级',readonly=1) stu_status = fields.Selection([ ('studying', '在读'), ('graduated', '已毕业'), @@ -42,13 +44,57 @@ class StudentInfo(models.Model): 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的问题) + user_id = fields.Many2one('res.users', string="系统登录账号", ondelete='restrict') - # 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 + record.org_path = False + + @api.model + def create(self, vals): + # 1. 先校验学号,提前取出学号避免多次读取 + stu_num = vals.get('stu_num', '').strip() + new_user = None + + # 2. 学号不为空才执行创建用户逻辑 + if stu_num: + # 校验学号对应的登录账号是否已存在 + exist_user = self.env['res.users'].search([('login', '=', stu_num)], limit=1) + if not exist_user: + # 获取两个权限组,并双重校验存在性 + internal_group = self.env.ref('base.group_user', raise_if_not_found=False) + student_group = self.env.ref('edu_base.group_student', raise_if_not_found=False) + + if not internal_group: + raise ValidationError("系统内置内部用户组 base.group_user 缺失,无法创建登录账号!") + if not student_group: + raise ValidationError("权限组 edu_base.group_student 不存在,请先创建该学生权限组!") + + # 组装用户参数,优先取学生填写的邮箱,无则自动生成 + stu_email = vals.get('stu_email') + if not stu_email: + stu_email = f"{stu_num}@edu.local" + + user_vals = { + 'name': vals.get('stu_name', ''), + 'login': stu_num, + 'password': stu_num, + 'email': stu_email, + 'phone': vals.get('stu_phone', ''), + # 同时分配后台登录组 + 学生业务权限组 + 'groups_id': [(6, 0, [student_group.id, internal_group.id])], + } + # 先创建用户,事务内失败会整体回滚 + new_user = self.env['res.users'].create(user_vals) + + # 3. 创建学生档案,如果已生成用户则绑定user_id + if new_user: + vals['user_id'] = new_user.id + student_info = super().create(vals) + + return student_info \ No newline at end of file diff --git a/student_organization/views/view_student_info.xml b/student_organization/views/view_student_info.xml index 4cfd0ec..4857473 100644 --- a/student_organization/views/view_student_info.xml +++ b/student_organization/views/view_student_info.xml @@ -3,7 +3,7 @@ student.info.list student.info - +