diff --git a/__manifest__.py b/__manifest__.py
index 3bb458c..f7497d1 100644
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -1,17 +1,32 @@
+# -*- coding: utf-8 -*-
{
- 'name': 'Gestao Escolar',
- 'version': '1.0',
- 'summary': 'Sistema de Gestão Escolar',
- 'author': 'Sebastiao',
+ 'name': 'Gestão Escolar Avançada - CEFOPE Core',
+ 'version': '1.0.0',
+ 'summary': 'Sistema de Gestão Escolar para as Instituíções de Angola',
+ 'description': """
+ Módulo central do projeto CEFOPE:
+ - Gestão de Candidatos e Exames
+ - Configuração de Cursos e Turmas
+ - Controlo de Matrículas e Notas
+ """,
+ 'author': 'Hilaritech',
'category': 'Education',
- 'depends': ['base'],
+ 'license': 'LGPL-3',
+
+ 'depends': [
+ 'base',
+ ],
'data': [
- 'security/groups.xml',
+ 'security/cefope_security_groups.xml',
'security/ir.model.access.csv',
- 'views/school_views.xml',
+ 'views/academic_applicant_views.xml',
+ 'views/academic_course_views.xml',
+ 'views/academic_exam_views.xml',
+ 'views/menus.xml',
],
'installable': True,
'application': True,
-}
+ 'auto_install': False,
+}
\ No newline at end of file
diff --git a/__pycache__/__init__.cpython-313.pyc b/__pycache__/__init__.cpython-313.pyc
index 58bcd69..181bb60 100644
Binary files a/__pycache__/__init__.cpython-313.pyc and b/__pycache__/__init__.cpython-313.pyc differ
diff --git a/models/__init__.py b/models/__init__.py
index a2369d6..f5a8fbe 100644
--- a/models/__init__.py
+++ b/models/__init__.py
@@ -1,7 +1,3 @@
-from . import student
-from . import teacher
-from . import academic_year
-from . import school_class
-from . import subject
-from . import enrollment
-from . import assessment
+from . import academic_applicant
+from . import academic_exam
+from . import academic_course
\ No newline at end of file
diff --git a/models/__pycache__/__init__.cpython-313.pyc b/models/__pycache__/__init__.cpython-313.pyc
index 31f2ca5..db4a6ed 100644
Binary files a/models/__pycache__/__init__.cpython-313.pyc and b/models/__pycache__/__init__.cpython-313.pyc differ
diff --git a/models/__pycache__/academic_applicant.cpython-313.pyc b/models/__pycache__/academic_applicant.cpython-313.pyc
new file mode 100644
index 0000000..083a8be
Binary files /dev/null and b/models/__pycache__/academic_applicant.cpython-313.pyc differ
diff --git a/models/__pycache__/academic_course.cpython-313.pyc b/models/__pycache__/academic_course.cpython-313.pyc
new file mode 100644
index 0000000..de00595
Binary files /dev/null and b/models/__pycache__/academic_course.cpython-313.pyc differ
diff --git a/models/__pycache__/academic_exam.cpython-313.pyc b/models/__pycache__/academic_exam.cpython-313.pyc
new file mode 100644
index 0000000..552fc96
Binary files /dev/null and b/models/__pycache__/academic_exam.cpython-313.pyc differ
diff --git a/models/__pycache__/academic_year.cpython-313.pyc b/models/__pycache__/academic_year.cpython-313.pyc
deleted file mode 100644
index 33a702b..0000000
Binary files a/models/__pycache__/academic_year.cpython-313.pyc and /dev/null differ
diff --git a/models/__pycache__/assessment.cpython-313.pyc b/models/__pycache__/assessment.cpython-313.pyc
deleted file mode 100644
index 5215691..0000000
Binary files a/models/__pycache__/assessment.cpython-313.pyc and /dev/null differ
diff --git a/models/__pycache__/enrollment.cpython-313.pyc b/models/__pycache__/enrollment.cpython-313.pyc
deleted file mode 100644
index 25ff4bc..0000000
Binary files a/models/__pycache__/enrollment.cpython-313.pyc and /dev/null differ
diff --git a/models/__pycache__/school_class.cpython-313.pyc b/models/__pycache__/school_class.cpython-313.pyc
deleted file mode 100644
index a1e05ec..0000000
Binary files a/models/__pycache__/school_class.cpython-313.pyc and /dev/null differ
diff --git a/models/__pycache__/student.cpython-313.pyc b/models/__pycache__/student.cpython-313.pyc
deleted file mode 100644
index 469bc87..0000000
Binary files a/models/__pycache__/student.cpython-313.pyc and /dev/null differ
diff --git a/models/__pycache__/subject.cpython-313.pyc b/models/__pycache__/subject.cpython-313.pyc
deleted file mode 100644
index ea9660d..0000000
Binary files a/models/__pycache__/subject.cpython-313.pyc and /dev/null differ
diff --git a/models/__pycache__/teacher.cpython-313.pyc b/models/__pycache__/teacher.cpython-313.pyc
deleted file mode 100644
index 6ef9f41..0000000
Binary files a/models/__pycache__/teacher.cpython-313.pyc and /dev/null differ
diff --git a/models/academic_applicant.py b/models/academic_applicant.py
new file mode 100644
index 0000000..131f4b3
--- /dev/null
+++ b/models/academic_applicant.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+from odoo import fields, models, api
+from odoo.exceptions import ValidationError
+
+
+class AcademicApplicant(models.Model):
+ _name = 'academic.applicant'
+ _description = 'Candidato Académico'
+ _order = 'id desc'
+
+ # --- Dados Pessoais ---
+ name = fields.Char(string="Nome Completo", required=True)
+ birth_date = fields.Date(string="Data de Nascimento", required=True)
+ gender = fields.Selection([
+ ('M', 'Masculino'),
+ ('F', 'Feminino')
+ ], string="Género", required=True)
+ bi = fields.Char(string="Número de Identidade (BI)", required=True)
+
+ # --- Documentos (Binary) ---
+ photo_bi = fields.Binary(string="Foto do BI (Frente e Verso)", attachment=True, required=True)
+ certificate = fields.Binary(string="Certificado de Conclusão", attachment=True, required=True)
+
+ # --- Histórico Escolar ---
+ previous_school = fields.Char(string="Escola Anterior", required=True)
+ previous_school_type = fields.Selection([
+ ('public', 'Pública'),
+ ('private', 'Privada'),
+ ('ppp', 'Parceria Público-Privada')
+ ], string="Tipo de Escola", default='public', required=True)
+ graduation_year = fields.Integer(string="Ano de Conclusão", required=True)
+
+ # --- Contactos ---
+ phone = fields.Char(string="Telefone")
+ email = fields.Char(string="Email")
+
+ # --- Relações ---
+ course_id = fields.Many2one('academic.course', string="Curso Pretendido", required=True)
+ exam_id = fields.Many2one("academic.exam", string="Exame de Acesso")
+ exam_score = fields.Float(string="Nota do Exame", digits=(1, 2))
+
+ # Relacionamento com o Utilizador (Para Record Rules)
+ user_id = fields.Many2one('res.users', string="Utilizador", default=lambda self: self.env.user)
+
+ # --- Workflow de Estado ---
+ state = fields.Selection([
+ ('draft', 'Rascunho'),
+ ('submitted', 'Submetido'),
+ ('exam', 'Exame Marcado'),
+ ('taken', 'Exame Realizado'),
+ ('approved', 'Aprovado'),
+ ('rejected', 'Rejeitado')
+ ], string="Estado", default='draft')
+
+
+ # --- Funções de Fluxo (Botões do Header) ---
+
+ def action_submit(self):
+ """Apenas valida documentos e avança para Submetido"""
+ for record in self:
+ if not record.photo_bi or not record.bi:
+ raise ValidationError("Erro: É obrigatório anexar a foto do BI e preencher o número do BI!")
+ record.state = 'submitted'
+
+ def action_mark_exam(self):
+ """Esta é a função que exige o exame. Só deve ser clicada APÓS a submissão"""
+ for record in self:
+ if not record.exam_id:
+ raise ValidationError("Erro: Selecione primeiro o Exame de Acesso no campo correspondente.")
+ record.state = 'exam'
+
+ @api.onchange('exam_score')
+ def _onchange_exam_score(self):
+ """Quando a nota muda (mesmo na lista de chamada), atualiza o estado"""
+ for record in self:
+ if record.exam_score >= 10:
+ record.state = 'approved'
+ elif 0 < record.exam_score < 10:
+ record.state = 'rejected'
\ No newline at end of file
diff --git a/models/academic_course.py b/models/academic_course.py
new file mode 100644
index 0000000..4c584ec
--- /dev/null
+++ b/models/academic_course.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+from odoo import fields, models
+
+
+class AcademicCourse(models.Model):
+ _name = 'academic.course'
+ _description = 'Curso Académico'
+ _order = 'name'
+
+ name = fields.Char(string="Nome do Curso", required=True)
+ code = fields.Char(string="Código do Curso", help="Ex: TI-01, MEC-02")
+ duration = fields.Integer(string="Duração (Anos)", default=4)
+ description = fields.Text(string="Descrição/Perfil de Saída")
+
+ # Campo para definir se o curso está ativo para novas inscrições
+ active = fields.Boolean(string="Ativo", default=True)
+
+ # Relacionamento: Um curso tem muitos candidatos
+ applicant_ids = fields.One2many(
+ 'academic.applicant',
+ 'course_id',
+ string="Candidatos Inscritos"
+ )
+
+ _sql_constraints = [
+ ('name_unique', 'unique(name)', 'O nome do curso deve ser único!'),
+ ('code_unique', 'unique(code)', 'O código do curso deve ser único!')
+ ]
\ No newline at end of file
diff --git a/models/academic_exam.py b/models/academic_exam.py
new file mode 100644
index 0000000..60f3e05
--- /dev/null
+++ b/models/academic_exam.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+from odoo import fields, models, api
+
+
+class AcademicExam(models.Model):
+ _name = 'academic.exam'
+ _description = 'Exame de Acesso'
+ _order = 'date desc'
+
+ name = fields.Char(string="Identificação do Exame", required=True, help="Ex: Exame de Informática - Sala 13")
+ date = fields.Datetime(string="Data e Hora", required=True)
+ room = fields.Char(string="Sala/Local", required=True)
+ capacity = fields.Integer(string="Capacidade Máxima", default=30)
+
+ # Relacionamento com o curso (opcional, se o exame for por curso)
+ course_id = fields.Many2one('academic.course', string="Curso Relacionado")
+
+ # Lista de candidatos inscritos neste exame específico
+ applicant_ids = fields.One2many(
+ 'academic.applicant',
+ 'exam_id',
+ string="Candidatos Inscritos"
+ )
+
+ # Campo calculado para saber quantos já estão inscritos
+ applicant_count = fields.Integer(
+ string="Total Inscritos",
+ compute='_compute_applicant_count',
+ store=True
+ )
+
+ @api.depends('applicant_ids')
+ def _compute_applicant_count(self):
+ for record in self:
+ record.applicant_count = len(record.applicant_ids)
\ No newline at end of file
diff --git a/models/academic_year.py b/models/academic_year.py
deleted file mode 100644
index d0729c8..0000000
--- a/models/academic_year.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from odoo import models, fields
-
-class AcademicYear(models.Model):
- _name = 'school.academic.year'
- _description = 'Academic Year'
-
- name = fields.Char(required=True)
- start_date = fields.Date()
- end_date = fields.Date()
diff --git a/models/assessment.py b/models/assessment.py
deleted file mode 100644
index 4447f29..0000000
--- a/models/assessment.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from odoo import models, fields
-
-class SchoolAssessment(models.Model):
- _name = 'school.assessment'
- _description = 'Assessment'
-
- enrollment_id = fields.Many2one(
- 'school.enrollment',
- string="Enrollment"
- )
-
- subject_id = fields.Many2one(
- 'school.subject',
- string="Subject"
- )
-
- grade = fields.Float(string="Grade")
diff --git a/models/enrollment.py b/models/enrollment.py
deleted file mode 100644
index d961bd8..0000000
--- a/models/enrollment.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from odoo import models, fields
-
-class SchoolEnrollment(models.Model):
- _name = 'school.enrollment'
- _description = 'Enrollment'
-
- student_id = fields.Many2one(
- 'cefope.student',
- string="Student"
- )
-
- class_id = fields.Many2one(
- 'school.class',
- string="Class"
- )
-
- academic_year_id = fields.Many2one(
- 'school.academic.year',
- string="Academic Year"
- )
-
- status = fields.Selection([
- ('active','Active'),
- ('completed','Completed'),
- ('cancelled','Cancelled')
- ], default='active')
diff --git a/models/school_class.py b/models/school_class.py
deleted file mode 100644
index cbc1b7f..0000000
--- a/models/school_class.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from odoo import models, fields
-
-class SchoolClass(models.Model):
- _name = 'school.class'
- _description = 'Class'
-
- name = fields.Char(required=True)
-
- academic_year_id = fields.Many2one(
- 'school.academic.year',
- string="Academic Year"
- )
-
- teacher_id = fields.Many2one(
- 'school.teacher',
- string="Teacher"
- )
diff --git a/models/student.py b/models/student.py
deleted file mode 100644
index 131679c..0000000
--- a/models/student.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from odoo import models, fields
-
-class Student(models.Model):
- _name = 'cefope.student'
- _description = 'Student'
-
- name = fields.Char(string="Name")
- email = fields.Char(string="Email")
- phone = fields.Char(string="Phone")
-
- user_id = fields.Many2one(
- 'res.users',
- string="User"
- )
diff --git a/models/subject.py b/models/subject.py
deleted file mode 100644
index 7409f35..0000000
--- a/models/subject.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from odoo import models, fields
-
-class SchoolSubject(models.Model):
- _name = 'school.subject'
- _description = 'Subject'
-
- name = fields.Char(required=True)
-
- class_id = fields.Many2one(
- 'school.class',
- string="Class"
- )
diff --git a/models/teacher.py b/models/teacher.py
deleted file mode 100644
index 95da0bd..0000000
--- a/models/teacher.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from odoo import models, fields
-
-class SchoolTeacher(models.Model):
- _name = 'school.teacher'
- _description = 'Teacher'
-
- name = fields.Char(required=True)
- email = fields.Char()
- phone = fields.Char()
diff --git a/security/cefope_security_groups.xml b/security/cefope_security_groups.xml
new file mode 100644
index 0000000..9e3126a
--- /dev/null
+++ b/security/cefope_security_groups.xml
@@ -0,0 +1,31 @@
+
+
+ Gestão Escolar CEFOPE
+ Níveis de acesso para o sistema escolar
+ 10
+
+
+
+ Administrador Escolar
+
+
+
+
+
+
+ Responsável Financeiro
+
+
+
+
+
+ Professor
+
+
+
+
+
+ Estudante
+
+
+
\ No newline at end of file
diff --git a/security/cefope_security_rules.xml b/security/cefope_security_rules.xml
new file mode 100644
index 0000000..0fcb9fb
--- /dev/null
+++ b/security/cefope_security_rules.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+ Candidato: Ver apenas a sua própria ficha
+
+
+ [('user_id', '=', user.id)]
+
+
+
+ Professor: Gerir apenas os seus exames
+
+
+ [('create_uid', '=', user.id)]
+
+
+
+ Financeiro: Ver todos os candidatos
+
+
+ [(1, '=', 1)]
+
+
+
+ Admin: Acesso Total
+
+
+ [(1, '=', 1)]
+
+
+
+
\ No newline at end of file
diff --git a/security/groups.xml b/security/groups.xml
deleted file mode 100644
index f9a11c0..0000000
--- a/security/groups.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- Student
-
-
-
- Teacher
-
-
-
- School Manager
-
-
-
diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv
index b433f95..86feb0e 100644
--- a/security/ir.model.access.csv
+++ b/security/ir.model.access.csv
@@ -1,8 +1,13 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_student,access_student,model_cefope_student,,1,1,1,1
-access_teacher,access_teacher,model_school_teacher,,1,1,1,1
-access_academic_year,access_academic_year,model_school_academic_year,,1,1,1,1
-access_class,access_class,model_school_class,,1,1,1,1
-access_subject,access_subject,model_school_subject,,1,1,1,1
-access_enrollment,access_enrollment,model_school_enrollment,,1,1,1,1
-access_assessment,access_assessment,model_school_assessment,,1,1,1,1
+access_academic_applicant_admin,academic.applicant,model_academic_applicant,cefope_core.group_cefope_administrator,1,1,1,1
+access_academic_applicant_finance,academic.applicant,model_academic_applicant,cefope_core.group_cefope_finance,1,1,1,0
+access_academic_applicant_teacher,academic.applicant,model_academic_applicant,cefope_core.group_cefope_teacher,1,1,0,0
+access_academic_applicant_student,academic.applicant,model_academic_applicant,cefope_core.group_cefope_student,1,1,0,0
+access_academic_course_admin,academic.course,model_academic_course,cefope_core.group_cefope_administrator,1,1,1,1
+access_academic_course_finance,academic.course,model_academic_course,cefope_core.group_cefope_finance,1,0,0,0
+access_academic_course_teacher,academic.course,model_academic_course,cefope_core.group_cefope_teacher,1,0,0,0
+access_academic_course_student,academic.course,model_academic_course,cefope_core.group_cefope_student,1,0,0,0
+access_academic_exam_admin,academic.exam,model_academic_exam,cefope_core.group_cefope_administrator,1,1,1,1
+access_academic_exam_finance,academic.exam,model_academic_exam,cefope_core.group_cefope_finance,1,0,0,0
+access_academic_exam_teacher,academic.exam,model_academic_exam,cefope_core.group_cefope_teacher,1,1,1,1
+access_academic_exam_student,academic.exam,model_academic_exam,cefope_core.group_cefope_student,1,0,0,0
\ No newline at end of file
diff --git a/security/rules.xml b/security/rules.xml
deleted file mode 100644
index 07456ec..0000000
--- a/security/rules.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- Student sees only his record
-
-
- [('user_id','=',user.id)]
-
-
-
diff --git a/views/academic_applicant_views.xml b/views/academic_applicant_views.xml
new file mode 100644
index 0000000..0b76ce8
--- /dev/null
+++ b/views/academic_applicant_views.xml
@@ -0,0 +1,106 @@
+
+
+
+ academic.applicant.list
+ academic.applicant
+
+
+
+
+
+
+
+
+
+
+
+
+ academic.applicant.form
+ academic.applicant
+
+
+
+
+
+
+ Candidatos
+ academic.applicant
+ list,form
+
+
\ No newline at end of file
diff --git a/views/academic_course_views.xml b/views/academic_course_views.xml
new file mode 100644
index 0000000..b031601
--- /dev/null
+++ b/views/academic_course_views.xml
@@ -0,0 +1,59 @@
+
+
+
+ academic.course.list
+ academic.course
+
+
+
+
+
+
+
+
+
+
+
+ academic.course.form
+ academic.course
+
+
+
+
+
+
+ Cursos
+ academic.course
+ list,form
+
+
\ No newline at end of file
diff --git a/views/academic_exam_views.xml b/views/academic_exam_views.xml
new file mode 100644
index 0000000..9e55c07
--- /dev/null
+++ b/views/academic_exam_views.xml
@@ -0,0 +1,69 @@
+
+
+
+ academic.exam.list
+ academic.exam
+
+
+
+
+
+
+
+
+
+
+
+
+ academic.exam.calendar
+ academic.exam
+
+
+
+
+
+
+
+
+
+ academic.academic.exam.form
+ academic.exam
+
+
+
+
+
+
+ Exames de Acesso
+ academic.exam
+ list,calendar,form
+
+
\ No newline at end of file
diff --git a/views/academic_views.xml b/views/academic_views.xml
deleted file mode 100644
index e69de29..0000000
diff --git a/views/assessment_views.xml b/views/assessment_views.xml
deleted file mode 100644
index e69de29..0000000
diff --git a/views/class_views.xml b/views/class_views.xml
deleted file mode 100644
index e69de29..0000000
diff --git a/views/enrollment_views.xml b/views/enrollment_views.xml
deleted file mode 100644
index e69de29..0000000
diff --git a/views/menus.xml b/views/menus.xml
new file mode 100644
index 0000000..414dde2
--- /dev/null
+++ b/views/menus.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/views/school_views.xml b/views/school_views.xml
deleted file mode 100644
index 1fce6aa..0000000
--- a/views/school_views.xml
+++ /dev/null
@@ -1,313 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- student.list
- cefope.student
-
-
-
-
-
-
-
-
-
-
-
- student.form
- cefope.student
-
-
-
-
-
-
- Students
- cefope.student
- list,form
-
-
-
-
-
-
-
-
-
- teacher.list
- school.teacher
-
-
-
-
-
-
-
-
-
-
- teacher.form
- school.teacher
-
-
-
-
-
-
- Teachers
- school.teacher
- list,form
-
-
-
-
-
-
-
-
-
- academic.year.list
- school.academic.year
-
-
-
-
-
-
-
-
-
-
- academic.year.form
- school.academic.year
-
-
-
-
-
-
- Academic Years
- school.academic.year
- list,form
-
-
-
-
-
-
-
-
-
- class.list
- school.class
-
-
-
-
-
-
-
-
-
-
- class.form
- school.class
-
-
-
-
-
-
- Classes
- school.class
- list,form
-
-
-
-
-
-
-
-
-
- subject.list
- school.subject
-
-
-
-
-
-
-
-
-
- subject.form
- school.subject
-
-
-
-
-
-
- Subjects
- school.subject
- list,form
-
-
-
-
-
-
-
-
-
- enrollment.list
- school.enrollment
-
-
-
-
-
-
-
-
-
-
-
- enrollment.form
- school.enrollment
-
-
-
-
-
-
- Enrollments
- school.enrollment
- list,form
-
-
-
-
-
-
-
-
-
- assessment.list
- school.assessment
-
-
-
-
-
-
-
-
-
-
- assessment.form
- school.assessment
-
-
-
-
-
-
- Assessments
- school.assessment
- list,form
-
-
-
-
-
diff --git a/views/student_views.xml b/views/student_views.xml
deleted file mode 100644
index e69de29..0000000
diff --git a/views/subject_views.xml b/views/subject_views.xml
deleted file mode 100644
index e69de29..0000000
diff --git a/views/teacher_views.xml b/views/teacher_views.xml
deleted file mode 100644
index e69de29..0000000