update education module

This commit is contained in:
2025-02-26 16:28:17 +07:00
parent bc4a67a616
commit f79a7fe0b9
19 changed files with 378 additions and 137 deletions
+9
View File
@@ -2,3 +2,12 @@
from . import controllers from . import controllers
from . import models from . import models
from . import wizard
def add_school_hook(env): # Ensure both cr and registry are accepted
data = [
{"name": "Haiphong University", "code": "THP"},
{"name": "Hanoi University", "code": "HANU"},
]
env["education.school"].create(data) # Close the function properly
+20 -24
View File
@@ -1,37 +1,33 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
{ {
'name': "Education Management", "name": "Education Management",
"summary": "This Module is for Education purpose",
'summary': "This Module is for Education purpose", "description": """
'description': """
This Module is for Education purpose This Module is for Education purpose
""", """,
"author": "NextZen",
'author': "NextZen", "website": "https://nextzenos.com",
'website': "https://nextzenos.com",
# Categories can be used to filter modules in modules listing # Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml # Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml
# for the full list # for the full list
'category': 'Tutorial', "category": "Tutorial",
'version': '0.1', "version": "0.1",
# any module necessary for this one to work correctly # any module necessary for this one to work correctly
'depends': ['base'], "depends": ["base"],
# always loaded # always loaded
'data': [ "data": [
'security/education_security.xml', "security/education_security.xml",
'security/ir.model.access.csv', "security/ir.model.access.csv",
'views/education_menu_views.xml', "views/education_school_views.xml",
'views/education_student_views.xml', "views/education_class_views.xml",
'views/education_class_views.xml', "views/education_student_views.xml",
"views/education_student_level_views.xml",
"wizard/education_student_dropout_wizard.xml",
"views/menuitems.xml",
], ],
"post_init_hook": "add_school_hook",
# only loaded in demonstration mode # only loaded in demonstration mode
'demo': [ "demo": [
'demo/demo.xml', "demo/demo.xml",
], ],
} }
+1
View File
@@ -6,3 +6,4 @@ from . import education_student
from . import education_school from . import education_school
from . import education_student_level from . import education_student_level
from . import res_partner from . import res_partner
+32 -1
View File
@@ -25,5 +25,36 @@ class EducationClass(models.Model):
class_fund = fields.Monetary(string="Class Fund", currency_field="currency_id") class_fund = fields.Monetary(string="Class Fund", currency_field="currency_id")
student_ids = fields.One2many("education.student", "class_id", string="Students") student_ids = fields.One2many("education.student", "class_id", string="Students")
school_id = fields.Many2one("education.school", string="School", required=True) school_id = fields.Many2one("education.school", string="School", required=True)
active = fields.Boolean(string="Active", default=True) active = fields.Boolean(default=True)
teacher_ids = fields.Many2many("res.partner", string="Teachers") teacher_ids = fields.Many2many("res.partner", string="Teachers")
def get_all_students(self):
# Khởi tạo đối tượng education.student (đây là một recordset rỗng của model education.student)
student = self.env["education.student"]
all_students = student.search([])
print("All Students: ", all_students)
def create_classes(self):
# Giá trị để tạo bản ghi student 01
student_01 = {
"name": "Student 01",
"student_code": "STD1",
"school_id": self.school_id.id,
}
# Giá trị để tạo bản ghi student 02
student_02 = {
"name": "Student 02",
"student_code": "STD2",
"school_id": self.school_id.id,
}
# Giá trị để tạo bản ghi lớp học
class_value = {
"name": "Class 01",
"school_id": self.school_id.id,
"student_ids": [(0, 0, student_01), (0, 0, student_02)],
}
record = self.env["education.class"].create(class_value)
def change_class_name(self):
self.ensure_one()
self.name = "Class 12A1"
+17 -12
View File
@@ -1,22 +1,27 @@
from odoo import fields, models, api from odoo import fields, models, api
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
class EductionClassGroup(models.Model): class EductionClassGroup(models.Model):
_name = 'education.class.group' _name = "education.class.group"
_description = 'Education Class Group' _description = "Education Class Group"
_order = 'sequence' _order = "sequence"
sequence = fields.Integer(string="Sequence", default=0)
name = fields.Char(string='Name', translate=True, required=True) name = fields.Char(string="Name", translate=True, required=True)
# parent_id = fields.Many2one('education.class.group', string='Parent Group', ondelete='restrict') parent_id = fields.Many2one(
# child_ids = fields.One2many('education.class.group', string='Child Groups', ondelete='restrict') "education.class.group", string="Parent Group", ondelete="restrict"
)
# class_ids = fields.One2many('education.class', 'class_group_id', string='Class of Groups') child_ids = fields.One2many(
"education.class.group", "parent_id", string="Child Groups"
)
_parent_store = True _parent_store = True
_parent_name = "parent_id" _parent_name = "parent_id"
parent_path = fields.Char(index=True) parent_path = fields.Char(index=True)
class_ids = fields.One2many(
"education.class", "class_group_id", string="Class of Groups"
)
@api.constrains('parent_id') @api.constrains("parent_id")
def _check_hierarchy(self): def _check_hierarchy(self):
if not self._check_recursion(): if not self._check_recursion():
raise ValidationError('Error! You cannot create recursivecategories.') raise ValidationError("Error! You cannot create recursivecategories.")
+10 -6
View File
@@ -1,11 +1,15 @@
from odoo import fields, models from odoo import fields, models
class EductionSchool(models.Model): class EductionSchool(models.Model):
_name = 'education.school' _name = "education.school"
_description = 'School' _description = "School"
name = fields.Char(string='Name', translate=True, required=True) name = fields.Char(string="Name", translate=True, required=True)
code = fields.Char(string='Code', copy=False) code = fields.Char(string="Code", copy=False)
class_ids = fields.One2many('education.class', 'school_id', string='Classes') address = fields.Char(string="Address")
is_private = fields.Boolean(string='Is Private', groups='viin_education.viin_education_group_admin') class_ids = fields.One2many("education.class", "school_id", string="Classes")
is_private = fields.Boolean(
string="Is Private", groups="education.education_group_admin"
)
+65 -15
View File
@@ -1,6 +1,8 @@
from odoo import models, fields, api from odoo import models, fields, api
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from datetime import date from datetime import date
from odoo import _
from odoo.exceptions import UserError
class EducationStudent(models.Model): class EducationStudent(models.Model):
@@ -18,7 +20,7 @@ class EducationStudent(models.Model):
string="Gender", string="Gender",
default="male", default="male",
) )
date_of_birth = fields.Date(string="Date of Birth") date_of_birth = fields.Date(string="Date of Birth",)
age = fields.Integer( age = fields.Integer(
string="Age", string="Age",
compute="_compute_age", compute="_compute_age",
@@ -26,28 +28,26 @@ class EducationStudent(models.Model):
search="_search_age", search="_search_age",
store=False, # tùy chọn store=False, # tùy chọn
compute_sudo=True, compute_sudo=True,
readonly=True,
) )
active = fields.Boolean(string="Active", default=True) active = fields.Boolean(string="Active", default=True)
notes = fields.Text(string="Internal Notes") notes = fields.Text(string="Internal Notes")
description = fields.Html(string="Description", sanitize=True, strip_style=False) description = fields.Html(string="Description", sanitize=True, strip_style=False)
dropout_reason = fields.Text(string="Dropout Reason")
attached_file = fields.Binary("Attached File", groups="base.group_user") attached_file = fields.Binary("Attached File", groups="base.group_user")
total_score = fields.Float(string="Total Score", digits="Score") total_score = fields.Float(string="Total Score", digits="Score")
write_date = fields.Datetime(string="Last Updated on") write_date = fields.Datetime(string="Last Updated on")
currency_id = fields.Many2one("res.currency", string="Currency") currency_id = fields.Many2one("res.currency", string="Currency")
amount_paid = fields.Monetary("Amount Paid") amount_paid = fields.Monetary("Amount Paid", currency_field="currency_id")
class_id = fields.Many2one("education.class", string="Education Class") class_id = fields.Many2one("education.class", string="Class", ondelete="restrict")
@api.depends("date_of_birth") school_id = fields.Many2one("education.school", string="School")
def _compute_age(self): school_code = fields.Char(related="school_id.code", string="School Code")
curent_year = fields.Date.today().year school_address = fields.Char(related="school_id.address", string="School Address")
for r in self: state = fields.Selection(
if r.date_of_birth: string="Status",
r.age = curent_year - r.date_of_birth.year selection=[("new", "New"), ("studying", "Studying"), ("off", "Off")],
else: default="new",
r.age = 0 )
def get_student_has_class(self):
return self.env["education.student"].search([("class_id", "!=", False)])
_sql_constraints = [ _sql_constraints = [
( (
"student_code_unique", "student_code_unique",
@@ -61,6 +61,28 @@ class EducationStudent(models.Model):
), ),
] ]
@api.model
def is_allowed_state(self, current_state, new_state):
allowed_states = [
("new", "studying"),
("studying", "off"),
("off", "studying"),
("new", "off"),
]
return (current_state, new_state) in allowed_states
@api.depends("date_of_birth", "age")
def _compute_age(self):
curent_year = fields.Date.today().year
for r in self:
if r.date_of_birth:
r.age = curent_year - r.date_of_birth.year + 1
else:
r.age = 0
def get_student_has_class(self):
return self.env["education.student"].search([("class_id", "!=", False)])
@api.constrains("date_of_birth") @api.constrains("date_of_birth")
def _check_date_of_birth(self): def _check_date_of_birth(self):
for r in self: for r in self:
@@ -84,3 +106,31 @@ class EducationStudent(models.Model):
operator_map = {">": "<", ">=": "<=", "<": ">", "<=": ">="} operator_map = {">": "<", ">=": "<=", "<": ">", "<=": ">="}
new_operator = operator_map.get(operator, operator) new_operator = operator_map.get(operator, operator)
return [("date_of_birth", new_operator, new_value)] return [("date_of_birth", new_operator, new_value)]
def change_student_state(self, state):
for student in self:
if student.is_allowed_state(student.state, state):
student.state = state
else:
raise UserError(
_("Changing student status from %s to %s is not allowed.")
% (student.state, state)
)
def change_to_new(self):
self.change_student_state("new")
def change_to_studying(self):
self.change_student_state("studying")
def change_to_off(self):
self.change_student_state("off")
def find_student(self):
domain = ["|", ("name", "ilike", "John"), ("class_id.name", "=", "12A1")]
students = self.search(domain)
def action_dropout(self):
return self.env.ref("education.education_student_dropout_wizard_action").read()[
0
]
+9 -8
View File
@@ -1,11 +1,12 @@
from odoo import fields, models from odoo import fields, models
class StudentLevel(models.Model):
_name = 'education.student.level'
_description = 'Student Level'
_order = 'sequence, name'
_rec_name = 'code'
code = fields.Char(string='Code', required=True) class StudentLevel(models.Model):
name = fields.Char(string='Name', translate=True, required=True) _name = "education.student.level"
sequence = fields.Integer(string='Sequence', default=1) _description = "Student Level"
_order = "sequence, name"
_rec_name = "code"
code = fields.Char(string="Code", required=True)
name = fields.Char(string="Name", translate=True, required=True)
sequence = fields.Integer(string="Sequence", default=1)
@@ -39,5 +39,6 @@
</record> </record>
<record id="education_group_allow_manager_class" model="res.groups"> <record id="education_group_allow_manager_class" model="res.groups">
<field name="name">Allow class management</field> <field name="name">Allow class management</field>
<field name="implied_ids" eval="[(4, ref('education_group_admin'))]" />
</record> </record>
</odoo> </odoo>
+9 -4
View File
@@ -1,7 +1,12 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_education_school_user,education.school user,model_education_school,education_group_user,1,0,0,0 access_education_school_user,education.school user,model_education_school,education_group_user,1,0,0,0
access_education_school_admin,education.school admin,model_education_school,education_group_admin,1,1,1,1 access_education_school_admin,education.school admin,model_education_school,education_group_admin,1,1,1,1
access_education_class_allow_manager,education.class allow_manager,model_education_class,education_group_allow_manager_class,1,1,1,1 access_education_class_user,education.class user,model_education_class,education_group_user,1,0,0,0
access_education_class_group,education.class user,model_education_class_group,education_group_user,1,0,0,0 access_education_class_admin,education.class admin,model_education_class,education_group_admin,1,1,1,1
access_education_student,education.student user,model_education_student,education_group_user,1,0,0,0 access_education_class_group_user,education.class.group user,model_education_class_group,education_group_user,1,0,0,0
access_education_student_level,education.student.level user,model_education_student_level,education_group_user,1,0,0,0 access_education_class_group_admin,education.class.group admin,model_education_class_group,education_group_admin,1,1,1,1
access_education_student_user,education.student user,model_education_student,education_group_user,1,0,0,0
access_education_student_admin,education.student admin,model_education_student,education_group_admin,1,1,1,1
access_education_student_level_user,education.student.level user,model_education_student_level,education_group_user,1,0,0,0
access_education_student_level_admin,education.student.level admin,model_education_student_level,education_group_admin,1,1,1,1
access_education_student_dropout_wizard,education.student.dropout.wizard,model_education_student_dropout_wizard,education.education_group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_education_school_user education.school user model_education_school education_group_user 1 0 0 0
3 access_education_school_admin education.school admin model_education_school education_group_admin 1 1 1 1
4 access_education_class_allow_manager access_education_class_user education.class allow_manager education.class user model_education_class education_group_allow_manager_class education_group_user 1 1 0 1 0 1 0
5 access_education_class_group access_education_class_admin education.class user education.class admin model_education_class_group model_education_class education_group_user education_group_admin 1 0 1 0 1 0 1
6 access_education_student access_education_class_group_user education.student user education.class.group user model_education_student model_education_class_group education_group_user 1 0 0 0
7 access_education_student_level access_education_class_group_admin education.student.level user education.class.group admin model_education_student_level model_education_class_group education_group_user education_group_admin 1 0 1 0 1 0 1
8 access_education_student_user education.student user model_education_student education_group_user 1 0 0 0
9 access_education_student_admin education.student admin model_education_student education_group_admin 1 1 1 1
10 access_education_student_level_user education.student.level user model_education_student_level education_group_user 1 0 0 0
11 access_education_student_level_admin education.student.level admin model_education_student_level education_group_admin 1 1 1 1
12 access_education_student_dropout_wizard education.student.dropout.wizard model_education_student_dropout_wizard education.education_group_user 1 1 1 1
+42 -39
View File
@@ -1,44 +1,47 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<data> <record id="education_class_view_form" model="ir.ui.view">
<record id="education_class_view_form" model="ir.ui.view"> <field name="name">education.class.form</field>
<field name="name">education.class.form</field> <field name="model">education.class</field>
<field name="model">education.class</field> <field name="arch" type="xml">
<field name="arch" type="xml"> <form string="Class Form">
<form string="Class Form"> <sheet>
<sheet> <!-- <widget name="web_ribbon" title="Archived" bg_color="bg-danger" /> -->
<widget name="web_ribbon" title="Archived" bg_color="bg-danger"/> <field name="active" invisible="True" />
<field name="active" invisible="1" /> <header>
<button name="get_all_students" type="object" string="Log All Students" />
<button name="create_classes" type="object" string="Create Classes" />
<button name="change_class_name" type="object" string="Change Name" />
</header>
<group>
<group> <group>
<group> <field name="name" />
<field name="name" /> <field name="school_id" />
<field name="school_id" /> <field name="class_group_id" />
<field name="class_group_id" />
</group>
<group>
<field name="next_class_id" />
</group>
</group> </group>
</sheet> <group>
</form> <field name="next_class_id" />
</field> </group>
</record> </group>
<record id="education_class_view_list" model="ir.ui.view"> </sheet>
<field name="name">education.class.list</field> </form>
<field name="model">education.class</field> </field>
<field name="arch" type="xml"> </record>
<list string="Class list"> <record id="education_class_view_list" model="ir.ui.view">
<field name="name" /> <field name="name">education.class.list</field>
<field name="class_group_id" /> <field name="model">education.class</field>
<field name="next_class_id" /> <field name="arch" type="xml">
<field name="school_id" /> <list string="Class list">
</list> <field name="name" />
</field> <field name="class_group_id" />
</record> <field name="next_class_id" />
<record id="education_class_action" model="ir.actions.act_window"> <field name="school_id" />
<field name="name">Class</field> </list>
<field name="res_model">education.class</field> </field>
<field name="view_mode">list,form</field> </record>
</record> <record id="education_class_action" model="ir.actions.act_window">
</data> <field name="name">Class</field>
<field name="res_model">education.class</field>
<field name="view_mode">list,form</field>
</record>
</odoo> </odoo>
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem name="Education Manager" id="education_management_menu_root" />
<menuitem id="education_student_menu" action="education_student_action"
parent="education_management_menu_root" name="Students" sequence="50" />
<menuitem name="Configurations" id="education_configuration_menu_root" />
<menuitem id="education_class_allow_manager_menu"
name="Class"
action="education_class_action"
parent="education_configuration_menu_root"
sequence="10" />
</odoo>
+40 -1
View File
@@ -1,3 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<record id="education_school_view_form" model="ir.ui.view">
<field name="name">education.school.form</field>
<field name="model">education.school</field>
<field name="arch" type="xml">
<form string="school Form">
<sheet>
<!-- <widget name="web_ribbon" title="Archived" bg_color="bg-danger" /> -->
<group>
<group>
<field name="name" />
<field name="code" />
<field name="address" />
</group>
</group>
<notebook>
<page string="Classes" name="classes">
<field name="class_ids" widget="many2many_tags" />
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="education_school_view_list" model="ir.ui.view">
<field name="name">education.school.list</field>
<field name="model">education.school</field>
<field name="arch" type="xml">
<list string="school list">
<field name="name" />
<field name="code" />
<field name="address" />
</list>
</field>
</record>
<record id="education_school_action" model="ir.actions.act_window">
<field name="name">School</field>
<field name="res_model">education.school</field>
<field name="view_mode">list,form</field>
</record>
</odoo> </odoo>
@@ -6,16 +6,31 @@
<form string="Student Level Form"> <form string="Student Level Form">
<sheet> <sheet>
<group> <group>
<group> <group>
<field name="name"/> <field name="name" />
<field name="sequence"/> <field name="sequence" />
</group> </group>
<group> <group>
<field name="code"/> <field name="code" />
</group> </group>
</group> </group>
</sheet> </sheet>
</form> </form>
</field> </field>
</record> </record>
<record id="education_student_level_view_list" model="ir.ui.view">
<field name="name">education.student.level.list</field>
<field name="model">education.student.level</field>
<field name="arch" type="xml">
<list string="Student list">
<field name="code" />
<field name="name" />
</list>
</field>
</record>
<record id="education_student_level_action" model="ir.actions.act_window">
<field name="name">Student Level</field>
<field name="res_model">education.student.level</field>
<field name="view_mode">list,form</field>
</record>
</odoo> </odoo>
+18 -6
View File
@@ -5,6 +5,13 @@
<field name="model">education.student</field> <field name="model">education.student</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Student Form"> <form string="Student Form">
<header>
<button name="change_to_new" type="object" string="New" />
<button name="change_to_studying" type="object" string="Studying" />
<button name="change_to_off" type="object" string="Off" />
<button name="action_dropout" string="Dropout" type="object" />
<field name="state" widget="statusbar" />
</header>
<sheet> <sheet>
<group> <group>
<group> <group>
@@ -17,6 +24,7 @@
<field name="amount_paid" /> <field name="amount_paid" />
</group> </group>
<group> <group>
<field name="class_id" />
<field name="total_score" /> <field name="total_score" />
<field name="attached_file" /> <field name="attached_file" />
<field name="write_date" /> <field name="write_date" />
@@ -25,9 +33,14 @@
<group> <group>
<field name="notes" /> <field name="notes" />
</group> </group>
<group> <notebook>
<field name="description" /> <page string="Description" name="description">
</group> <field name="description" />
</page>
<page string="Dropout Reason" name="dropout">
<field name="dropout_reason" />
</page>
</notebook>
</sheet> </sheet>
</form> </form>
</field> </field>
@@ -48,9 +61,9 @@
<field name="model">education.student</field> <field name="model">education.student</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Students Search"> <search string="Students Search">
<field name="name" <field name="name" />
filter_domain="['|', '|', ('name', 'ilike', self), ('student_code', '=', self)" />
<field name="class_id" /> <field name="class_id" />
<filter name="total_score" domain="[('total_score', '>', 10)]" />
</search> </search>
</field> </field>
</record> </record>
@@ -59,5 +72,4 @@
<field name="res_model">education.student</field> <field name="res_model">education.student</field>
<field name="view_mode">list,form</field> <field name="view_mode">list,form</field>
</record> </record>
</odoo> </odoo>
+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem id="education_management_menu_root" name="Education Manager" sequence="210" />
<menuitem id="education_configuration_menu_root" name="Configurations"
parent="education_management_menu_root" sequence="200" />
<menuitem id="education_student_menu" action="education_student_action"
parent="education_management_menu_root" name="Students" sequence="10" />
<menuitem id="education_class_configuration_menu"
name="Class"
action="education_class_action"
parent="education_configuration_menu_root"
sequence="10" />
<menuitem id="education_student_level_configuration_menu"
name="Student Level"
action="education_student_level_action"
parent="education_configuration_menu_root"
sequence="20" />
<menuitem id="education_school_configuration_menu"
name="School"
action="education_school_action"
parent="education_configuration_menu_root"
sequence="30" />
</odoo>
+1
View File
@@ -0,0 +1 @@
from . import education_student_dropout_wizard
@@ -0,0 +1,27 @@
from odoo import fields, models
class EducationStudentDropoutWizard(models.TransientModel):
_name = "education.student.dropout.wizard"
_description = "Education Student Dropout Wizard"
def _default_student(self):
active_model = self.env.context.get("active_model")
active_id = self.env.context.get("active_id")
return self.env[active_model].browse(active_id)
student_id = fields.Many2one(
"education.student", string="Student", default=_default_student, required=True
)
dropout_reason = fields.Text(string="Dropout Reason", required=True)
def action_confirm(self):
self.ensure_one()
self.student_id.dropout_reason = self.dropout_reason
self.student_id.state = "off"
result = self.env.ref("education.education_class_action").read()[0]
res = self.env.ref("education.education_class_view_form", False)
result["views"] = [(res and res.id or False, "form")]
result["res_id"] = self.student_id.class_id.id
return result
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="education_student_dropout_wizard_action" model="ir.actions.act_window">
<field name="name">Dropout Reason</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">education.student.dropout.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record id="education_student_dropout_wizard_form" model="ir.ui.view">
<field name="name">education.student.dropout.wizard.form</field>
<field name="model">education.student.dropout.wizard</field>
<field name="arch" type="xml">
<form string="Dropout Reason">
<group>
<field name="student_id" invisible="1" />
<field name="dropout_reason" />
</group>
<footer>
<button name="action_confirm" string="Confirm" type="object"
class="oe_highlight" />
<button special="cancel" string="Cancel" />
</footer>
</form>
</field>
</record>
</odoo>