diff --git a/education/__init__.py b/education/__init__.py index aa4d0fd..0481259 100644 --- a/education/__init__.py +++ b/education/__init__.py @@ -2,3 +2,12 @@ from . import controllers 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 diff --git a/education/__manifest__.py b/education/__manifest__.py index d50b298..29678a5 100644 --- a/education/__manifest__.py +++ b/education/__manifest__.py @@ -1,37 +1,33 @@ # -*- coding: utf-8 -*- { - 'name': "Education Management", - - 'summary': "This Module is for Education purpose", - - 'description': """ + "name": "Education Management", + "summary": "This Module is for Education purpose", + "description": """ This Module is for Education purpose """, - - 'author': "NextZen", - 'website': "https://nextzenos.com", - + "author": "NextZen", + "website": "https://nextzenos.com", # 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 # for the full list - 'category': 'Tutorial', - 'version': '0.1', - + "category": "Tutorial", + "version": "0.1", # any module necessary for this one to work correctly - 'depends': ['base'], - + "depends": ["base"], # always loaded - 'data': [ - 'security/education_security.xml', - 'security/ir.model.access.csv', - 'views/education_menu_views.xml', - 'views/education_student_views.xml', - 'views/education_class_views.xml', - + "data": [ + "security/education_security.xml", + "security/ir.model.access.csv", + "views/education_school_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 - 'demo': [ - 'demo/demo.xml', + "demo": [ + "demo/demo.xml", ], } - diff --git a/education/models/__init__.py b/education/models/__init__.py index 72ae638..7e38653 100644 --- a/education/models/__init__.py +++ b/education/models/__init__.py @@ -5,4 +5,5 @@ from . import education_class_group from . import education_student from . import education_school from . import education_student_level -from . import res_partner \ No newline at end of file +from . import res_partner + diff --git a/education/models/education_class.py b/education/models/education_class.py index 9ad184a..0b01243 100644 --- a/education/models/education_class.py +++ b/education/models/education_class.py @@ -25,5 +25,36 @@ class EducationClass(models.Model): class_fund = fields.Monetary(string="Class Fund", currency_field="currency_id") student_ids = fields.One2many("education.student", "class_id", string="Students") 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") + + 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" diff --git a/education/models/education_class_group.py b/education/models/education_class_group.py index d3a9cdb..a1209bd 100644 --- a/education/models/education_class_group.py +++ b/education/models/education_class_group.py @@ -1,22 +1,27 @@ from odoo import fields, models, api from odoo.exceptions import ValidationError + class EductionClassGroup(models.Model): - _name = 'education.class.group' - _description = 'Education Class Group' - _order = 'sequence' - - name = fields.Char(string='Name', translate=True, required=True) - # parent_id = fields.Many2one('education.class.group', string='Parent Group', ondelete='restrict') - # child_ids = fields.One2many('education.class.group', string='Child Groups', ondelete='restrict') - - # class_ids = fields.One2many('education.class', 'class_group_id', string='Class of Groups') - + _name = "education.class.group" + _description = "Education Class Group" + _order = "sequence" + sequence = fields.Integer(string="Sequence", default=0) + name = fields.Char(string="Name", translate=True, required=True) + parent_id = fields.Many2one( + "education.class.group", string="Parent Group", ondelete="restrict" + ) + child_ids = fields.One2many( + "education.class.group", "parent_id", string="Child Groups" + ) _parent_store = True _parent_name = "parent_id" parent_path = fields.Char(index=True) - - @api.constrains('parent_id') + class_ids = fields.One2many( + "education.class", "class_group_id", string="Class of Groups" + ) + + @api.constrains("parent_id") def _check_hierarchy(self): if not self._check_recursion(): - raise ValidationError('Error! You cannot create recursivecategories.') \ No newline at end of file + raise ValidationError("Error! You cannot create recursivecategories.") diff --git a/education/models/education_school.py b/education/models/education_school.py index 4c3f3e2..fb9b487 100644 --- a/education/models/education_school.py +++ b/education/models/education_school.py @@ -1,11 +1,15 @@ from odoo import fields, models + class EductionSchool(models.Model): - _name = 'education.school' - _description = 'School' + _name = "education.school" + _description = "School" - name = fields.Char(string='Name', translate=True, required=True) - code = fields.Char(string='Code', copy=False) - class_ids = fields.One2many('education.class', 'school_id', string='Classes') - is_private = fields.Boolean(string='Is Private', groups='viin_education.viin_education_group_admin') \ No newline at end of file + name = fields.Char(string="Name", translate=True, required=True) + code = fields.Char(string="Code", copy=False) + address = fields.Char(string="Address") + class_ids = fields.One2many("education.class", "school_id", string="Classes") + is_private = fields.Boolean( + string="Is Private", groups="education.education_group_admin" + ) diff --git a/education/models/education_student.py b/education/models/education_student.py index 1fcf973..b33a0dc 100644 --- a/education/models/education_student.py +++ b/education/models/education_student.py @@ -1,6 +1,8 @@ from odoo import models, fields, api from odoo.exceptions import ValidationError from datetime import date +from odoo import _ +from odoo.exceptions import UserError class EducationStudent(models.Model): @@ -18,7 +20,7 @@ class EducationStudent(models.Model): string="Gender", default="male", ) - date_of_birth = fields.Date(string="Date of Birth") + date_of_birth = fields.Date(string="Date of Birth",) age = fields.Integer( string="Age", compute="_compute_age", @@ -26,28 +28,26 @@ class EducationStudent(models.Model): search="_search_age", store=False, # tùy chọn compute_sudo=True, + readonly=True, ) active = fields.Boolean(string="Active", default=True) notes = fields.Text(string="Internal Notes") 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") total_score = fields.Float(string="Total Score", digits="Score") write_date = fields.Datetime(string="Last Updated on") currency_id = fields.Many2one("res.currency", string="Currency") - amount_paid = fields.Monetary("Amount Paid") - class_id = fields.Many2one("education.class", string="Education Class") - @api.depends("date_of_birth") - 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 - else: - r.age = 0 - - def get_student_has_class(self): - return self.env["education.student"].search([("class_id", "!=", False)]) - + amount_paid = fields.Monetary("Amount Paid", currency_field="currency_id") + class_id = fields.Many2one("education.class", string="Class", ondelete="restrict") + school_id = fields.Many2one("education.school", string="School") + school_code = fields.Char(related="school_id.code", string="School Code") + school_address = fields.Char(related="school_id.address", string="School Address") + state = fields.Selection( + string="Status", + selection=[("new", "New"), ("studying", "Studying"), ("off", "Off")], + default="new", + ) _sql_constraints = [ ( "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") def _check_date_of_birth(self): for r in self: @@ -84,3 +106,31 @@ class EducationStudent(models.Model): operator_map = {">": "<", ">=": "<=", "<": ">", "<=": ">="} new_operator = operator_map.get(operator, operator) 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 + ] diff --git a/education/models/education_student_level.py b/education/models/education_student_level.py index c2e5895..ed3eed1 100644 --- a/education/models/education_student_level.py +++ b/education/models/education_student_level.py @@ -1,11 +1,12 @@ 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) - name = fields.Char(string='Name', translate=True, required=True) - sequence = fields.Integer(string='Sequence', default=1) \ No newline at end of file +class StudentLevel(models.Model): + _name = "education.student.level" + _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) diff --git a/education/security/education_security.xml b/education/security/education_security.xml index ce6624a..1414009 100644 --- a/education/security/education_security.xml +++ b/education/security/education_security.xml @@ -39,5 +39,6 @@ Allow class management + \ No newline at end of file diff --git a/education/security/ir.model.access.csv b/education/security/ir.model.access.csv index d547e23..18ad57e 100644 --- a/education/security/ir.model.access.csv +++ b/education/security/ir.model.access.csv @@ -1,7 +1,12 @@ 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_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_group,education.class user,model_education_class_group,education_group_user,1,0,0,0 -access_education_student,education.student user,model_education_student,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 \ No newline at end of file +access_education_class_user,education.class user,model_education_class,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_class_group_user,education.class.group user,model_education_class_group,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 \ No newline at end of file diff --git a/education/views/education_class_views.xml b/education/views/education_class_views.xml index d45b79b..f0287e7 100644 --- a/education/views/education_class_views.xml +++ b/education/views/education_class_views.xml @@ -1,44 +1,47 @@ - - - education.class.form - education.class - -
- - - + + education.class.form + education.class + + + + + +
+
+ - - - - - - - - + + + -
- -
-
- - education.class.list - education.class - - - - - - - - - - - Class - education.class - list,form - -
+ + + + + + + + + + education.class.list + education.class + + + + + + + + + + + Class + education.class + list,form +
\ No newline at end of file diff --git a/education/views/education_menu_views.xml b/education/views/education_menu_views.xml deleted file mode 100644 index eadcb81..0000000 --- a/education/views/education_menu_views.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/education/views/education_school_views.xml b/education/views/education_school_views.xml index 056847f..52172b3 100644 --- a/education/views/education_school_views.xml +++ b/education/views/education_school_views.xml @@ -1,3 +1,42 @@ + - + + education.school.form + education.school + +
+ + + + + + + + + + + + + + + +
+
+
+ + education.school.list + education.school + + + + + + + + + + School + education.school + list,form +
\ No newline at end of file diff --git a/education/views/education_student_level_views.xml b/education/views/education_student_level_views.xml index 58e3659..e067f8e 100644 --- a/education/views/education_student_level_views.xml +++ b/education/views/education_student_level_views.xml @@ -6,16 +6,31 @@
- - - - - - - + + + + + + +
+ + education.student.level.list + education.student.level + + + + + + + + + Student Level + education.student.level + list,form + \ No newline at end of file diff --git a/education/views/education_student_views.xml b/education/views/education_student_views.xml index e23a6db..2685d27 100644 --- a/education/views/education_student_views.xml +++ b/education/views/education_student_views.xml @@ -5,6 +5,13 @@ education.student
+
+
@@ -17,6 +24,7 @@ + @@ -25,9 +33,14 @@ - - - + + + + + + + +
@@ -48,9 +61,9 @@ education.student - + + @@ -59,5 +72,4 @@ education.student list,form - \ No newline at end of file diff --git a/education/views/menuitems.xml b/education/views/menuitems.xml new file mode 100644 index 0000000..ac560e2 --- /dev/null +++ b/education/views/menuitems.xml @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/education/wizard/__init__.py b/education/wizard/__init__.py new file mode 100644 index 0000000..a4cfbe5 --- /dev/null +++ b/education/wizard/__init__.py @@ -0,0 +1 @@ +from . import education_student_dropout_wizard diff --git a/education/wizard/education_student_dropout_wizard.py b/education/wizard/education_student_dropout_wizard.py new file mode 100644 index 0000000..d4a4ed7 --- /dev/null +++ b/education/wizard/education_student_dropout_wizard.py @@ -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 diff --git a/education/wizard/education_student_dropout_wizard.xml b/education/wizard/education_student_dropout_wizard.xml new file mode 100644 index 0000000..6409c94 --- /dev/null +++ b/education/wizard/education_student_dropout_wizard.xml @@ -0,0 +1,30 @@ + + + + + Dropout Reason + ir.actions.act_window + education.student.dropout.wizard + form + new + + + + education.student.dropout.wizard.form + education.student.dropout.wizard + +
+ + + + + +
+
+
+ +
\ No newline at end of file