Commit 5d3d8145 by aagusti

tambah examp

1 parent b8b68f52
Showing 127 changed files with 2453 additions and 8 deletions
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import controllers
from . import models
# from . import wizard
# from . import report
{
'name': "Online Exam / Test / Quiz",
'version': "1.0.2",
'author': "Sythil Tech",
'category': "Tools",
'summary': "Informal Online Exam / Test / Quiz",
'license': 'GPL-3',
'data': [
'data/mail.template.csv',
# 'data/res.groups.csv',
'security/account_security.xml',
'security/ir.model.access.csv',
'security/ir_rule.xml',
'views/menus.xml',
'views/etq_exam.xml',
'views/etq_results.xml',
'views/exam_templates.xml',
# 'views/etq_exam_share.xml',
],
'demo': [],
'images': [
'static/description/2.jpg',
],
'depends': ['website', 'mail'],
'installable': True,
'application': True,
}
from . import main
\ No newline at end of file \ No newline at end of file
import logging
import odoo.http as http
import random
import uuid
from odoo.http import request
from werkzeug.utils import redirect
_logger = logging.getLogger(__name__)
class MyController(http.Controller):
@http.route('/exam/<exam_slug>', type="http", auth="public", website=True)
def take_exam(self, exam_slug):
exam = \
http.request.env['etq.exam'].sudo().search(
[('slug', '=', exam_slug)])
if not exam:
return request.render('website.page_404')
exam = exam[0]
exam_results = \
http.request.env['etq.result'].sudo().search(
[('exam_id', '=', exam.id),
('user_id', '=', request.env.user.id)])
if exam_results:
found = exam_results[0]
_logger.debug(found.state)
if found.state == 'complete':
# return redirect("/exam/results",/{}".format(found.token))
return self.exam_result(token=found.token)
# return "This attempt has already been used up"
token = found.token
else:
token = uuid.uuid4().__str__()
exam_result = http.request.env['etq.result'].sudo().create(
{'exam_id': exam.id, 'token': token, 'state': 'incomplete',
'user_id': request.env.user.id})
if exam.fill_mode == "random":
questions = random.sample(exam.questions,
exam.fill_mode_random_number)
for question in questions:
# Add random question to result
request.env['etq.result.question'].sudo().create(
{'result_id': exam_result.id,
'question_id': question.id})
else:
questions = exam.questions
for question in questions:
# Insert the question into the result
request.env['etq.result.question'].sudo().create(
{'result_id': exam_result.id,
'question_id': question.id})
return redirect("/exam/" + exam_slug + "/" + token)
@http.route('/exam/<exam_slug>/<string:token>', type="http", auth="public",
website=True)
def take_exam_token(self, exam_slug, token):
exam = \
http.request.env['etq.exam'].sudo().search(
[('slug', '=', exam_slug)])[0]
exam_result = request.env['etq.result'].search([('token', '=', token)])
if exam_result.state == "complete":
return "This attempt has already been used up"
else:
questions = exam_result.results
return http.request.render('exam_test_quiz.exam_question_page',
{'exam': exam, 'questions': questions,
'token': token})
@http.route('/exam/results', type="http", auth="public", website=True)
def exam_result(self, **kwargs):
values = {}
for field_name, field_value in kwargs.items():
values[field_name] = field_value
exam_results = ""
question_count = 0
correct_count = 0
if not values or 'token' not in values:
return redirect('/')
exam_results = request.env['etq.result'].search(
[('token', '=', values['token'])])
_logger.debug(exam_results)
if exam_results.state == "complete":
for rec in exam_results.results:
question_count += 1
if rec.correct:
correct_count += 1
percent = float(correct_count) / float(question_count) * 100
return request.render('exam_test_quiz.exam_results',
{'exam_result': exam_results,
'question_count': question_count,
'correct_count': correct_count,
'percent': percent})
if request.env.user.partner_id.name != 'Public user':
exam_results.user_id = request.env.user.id
for result_question in exam_results.results:
question_count += 1
exam_question = result_question.question_id
if exam_question.question_type == 'multi_choice':
if result_question.question_id.num_correct > 1:
question_result = True
# Go through each option in the question
for option in exam_question.question_options:
post_name = "question" + str(
exam_question.id) + "option" + str(option.id)
# They didn't have a checkbox checked for a correct option
if option.correct == True and \
(post_name in values) == False:
question_result = False
# They checked the wrong option
if option.correct == False and (
post_name in values) == True:
question_result = False
if post_name in values:
request.env[
'etq.result.question.option'].sudo().create(
{'question_id': result_question.id,
'option_id': int(values[post_name])})
if question_result == True:
correct_count += 1
result_question.correct = question_result
elif exam_question.num_correct == 1:
# Find the only correct option for the question
correct_option = request.env['etq.question.option'].search(
[('question_id', '=', exam_question.id),
('correct', '=', True)])[0].id
question_result = False
# They choose the correct option
if int(values["question" + str(exam_question.id)]) == int(
correct_option):
question_result = True
correct_count += 1
else:
question_result = False
result_question.correct = question_result
request.env['etq.result.question.option'].sudo().create(
{'question_id': result_question.id, 'option_id': int(
values["question" + str(exam_question.id)])})
elif exam_question.question_type == 'fill_blank':
question_result = True
option_count = 1
for option in exam_question.question_options_blank:
post_name = "question" + str(
exam_question.id) + "option" + str(option_count)
if values[post_name] != option.answer:
question_result = False
request.env['etq.result.question.option'].sudo().create(
{'question_id': result_question.id,
'question_options_value': values[post_name]})
option_count += 1
if question_result == True:
correct_count += 1
result_question.correct = question_result
percent = float(correct_count) / float(question_count) * 100
exam_results.state = "complete"
return request.render('exam_test_quiz.exam_results',
{'exam_result': exam_results,
'question_count': question_count,
'correct_count': correct_count,
'percent': percent})
"id","name","subject","body_html","email_from","email_to","model_id/id","auto_delete"
"exam_share_email","Exam Share Exam","Take our quiz","<p>Hello,</p><p>We are conducting a quiz, and your participation would be appreciated.</p><p><a href='__URL__'>__EXAM__ quiz</a></p><p>Thanks for your participation!</p>","${(object.user_id.email or object.company_id.email or 'noreply@' + object.company_id.name + '.com')|safe}","${object.email|safe}","base.model_res_partner","false"
"id","name","comment"
\ No newline at end of file \ No newline at end of file
v1.0.2
======
* Fix question counter and questions appearing on new paragraph
v1.0.1
======
* Fix fill in the blank being sanitized
v1.0
====
* Port to v10
\ No newline at end of file \ No newline at end of file
from . import etq_exam
from . import etq_results
from . import etq_exam_share
from odoo import models, fields, api
import logging
# import requests
from odoo.http import request
# from datetime import datetime
from odoo.tools import html_escape as escape, ustr
# , image_resize_and_sharpen, \
# image_save_for_web
import unicodedata
import re
_logger = logging.getLogger(__name__)
class EtqExam(models.Model):
_name = "etq.exam"
_description = "etq.exam"
name = fields.Char(string="Name", translate=True)
slug = fields.Char(string="Slug", compute="slug_me", store="True")
show_correct_questions = fields.Boolean(string="Show Correct Answers?")
questions = fields.One2many('etq.question', 'exam_id', string="Questions")
fill_mode = fields.Selection(
[('all', 'All Questions'), ('random', 'Random')], string="Fill Mode",
default="all")
fill_mode_random_number = fields.Integer(
string="Number of Random Questions")
@api.onchange('fill_mode')
def _onchange_fill_mode(self):
if self.fill_mode == "random":
self.fill_mode_random_number = len(self.questions)
# @api.multi
def view_quiz(self):
quiz_url = request.httprequest.host_url + "exam/" + str(self.slug)
return {
'type': 'ir.actions.act_url',
'target': 'new',
'url': quiz_url
}
# @api.one
@api.depends('name')
def slug_me(self):
for rec in self:
if rec.name:
s = ustr(rec.name)
uni = unicodedata.normalize('NFKD', s).encode('ascii',
'ignore').decode(
'ascii')
slug = re.sub('[\W_]', ' ', uni).strip().lower()
slug = re.sub('[-\s]+', '-', slug)
rec.slug = slug
class EtqQuestion(models.Model):
_name = "etq.question"
_description = "etq.question"
_rec_name = "question"
exam_id = fields.Many2one('etq.exam', string="Exam ID")
image = fields.Binary(string="Image")
question = fields.Html(string="Question")
question_rendered = fields.Html(string="Question Render",
compute="render_question", sanitize=False)
question_type = fields.Selection([('multi_choice', 'Multiple Choice'),
('fill_blank', 'Fill in the Blank')],
default="multi_choice",
string="Question Type")
question_options = fields.One2many('etq.question.option', 'question_id',
string="Multiple Choice Options")
question_options_blank = fields.One2many('etq.question.optionblank',
'question_id',
string="Fill in the Blank Options")
num_options = fields.Integer(string="Options", compute="calc_options")
num_correct = fields.Integer(string="Correct Options",
compute="calc_correct")
# @api.one
@api.depends('question')
def render_question(self):
for rec in self:
if rec.question:
temp_string = rec.question
temp_string = temp_string.replace(
"{1}",
"<i><input name=\"question" +
str(rec.id) +
"option1\" size=\"5\" style=\"border:none;border-bottom: 1px black solid;\" type=\"text\"/></i>")
temp_string = temp_string.replace(
"{2}",
"<i><input name=\"question" + str(rec.id) +
"option2\" size=\"5\" style=\"border:none;border-bottom: 1px black solid;\" type=\"text\"/></i>")
temp_string = temp_string.replace(
"{3}",
"<i><input name=\"question" + str(rec.id) +
"option3\" size=\"5\" style=\"border:none;border-bottom: 1px black solid;\" type=\"text\"/></i>")
temp_string = temp_string.replace("{4}",
"<i><input name=\"question" + str(
rec.id) + "option4\" size=\"5\" style=\"border:none;border-bottom: 1px black solid;\" type=\"text\"/></i>")
temp_string = temp_string.replace("{5}",
"<i><input name=\"question" + str(
rec.id) + "option5\" size=\"5\" style=\"border:none;border-bottom: 1px black solid;\" type=\"text\"/></i>")
temp_string = temp_string.replace("{6}",
"<i><input name=\"question" + str(
rec.id) + "option6\" size=\"5\" style=\"border:none;border-bottom: 1px black solid;\" type=\"text\"/></i>")
temp_string = temp_string.replace("{7}",
"<i><input name=\"question" + str(
rec.id) + "option7\" size=\"5\" style=\"border:none;border-bottom: 1px black solid;\" type=\"text\"/></i>")
temp_string = temp_string.replace("{8}",
"<i><input name=\"question" + str(
rec.id) + "option8\" size=\"5\" style=\"border:none;border-bottom: 1px black solid;\" type=\"text\"/></i>")
temp_string = temp_string.replace("{9}",
"<i><input name=\"question" + str(
rec.id) + "option9\" size=\"5\" style=\"border:none;border-bottom: 1px black solid;\" type=\"text\"/></i>")
_logger.info(temp_string)
rec.question_rendered = temp_string
#
# @api.one
@api.depends('question_options')
def calc_options(self):
for rec in self:
rec.num_options = rec.question_options.search_count(
[('question_id', '=', rec.id)])
#
# @api.one
@api.depends('question_options')
def calc_correct(self):
for rec in self:
rec.num_correct = self.question_options.search_count(
[('question_id', '=', rec.id), ('correct', '=', True)])
class EtqQuestionOptions(models.Model):
_name = "etq.question.option"
_description = "etq.question.option"
_rec_name = "option"
question_id = fields.Many2one('etq.question', string="Question ID")
option = fields.Char(string="Option")
correct = fields.Boolean(string="Correct")
class EtqQuestionOptionBlank(models.Model):
_name = "etq.question.optionblank"
_description = "etq.question.optionblank"
question_id = fields.Many2one('etq.question', string="Question ID")
answer = fields.Char(string="Blank Answer")
from odoo import models, fields, api
import logging
from odoo.http import request
# #
# import requests
# # from datetime import datetime
# # from openerp.tools import html_escape as escape, ustr, image_resize_and_sharpen, \
# # image_save_for_web
# # import unicodedata
# # import re
#
_logger = logging.getLogger(__name__)
class EtqExamShare(models.Model):
_name = "etq.exam.share"
_description = "etq.exam.share"
exam_id = fields.Many2one('etq.exam', string="Exam")
share_type = fields.Selection((('existing_contacts', 'Existing Contacts'),
('new_contacts', 'New Contacts')),
string="Share Option", required=True,
default="existing_contacts")
partner_ids = fields.Many2many('res.partner', string="Existing Contacts")
email_list = fields.Text(string="Email List")
# placeholder="Comma seperated emails")
email_subject = fields.Char(string="Email Subject", required=True)
email_content = fields.Html(string="Email Content", required=True,
sanitize=False)
@api.onchange('exam_id')
def _change_share(self):
notification_template = self.env['ir.model.data'].get_object(
'exam_test_quiz', 'exam_share_email')
for rec in self:
rec.email_subject = notification_template.subject
temp_content = notification_template.body_html
temp_content = temp_content.replace('__URL__',
request.httprequest.host_url + "exam/" + rec.exam_id.slug)
temp_content = temp_content.replace('__EXAM__', rec.exam_id.name)
rec.email_content = temp_content
# request.httprequest.host_url + "form/myinsert"
# @api.one
def share_exam(self):
for rec in self:
notification_template = self.env['ir.model.data'].get_object(
'exam_test_quiz', 'exam_share_email')
for cust in rec.partner_ids:
notification_template.subject = rec.email_subject
notification_template.body_html = rec.email_content
notification_template.send_mail(cust.id, True)
from odoo import models, fields, api
import logging
# import requests
# from odoo.http import request
#
# # from datetime import datetime
# # from openerp.tools import html_escape as escape, ustr, image_resize_and_sharpen, image_save_for_web
# # import unicodedata
# # import re
_logger = logging.getLogger(__name__)
#
#
class EtqResults(models.Model):
_name = "etq.result"
_description = "Exam Result"
exam_id = fields.Many2one('etq.exam', string="Exam", readonly=True)
user_id = fields.Many2one('res.users', string="User")
score = fields.Char(string="Score", compute="_compute_score")
results = fields.One2many('etq.result.question', 'result_id',
string="Results", readonly=True)
token = fields.Char(string="Token")
state = fields.Selection(
[('incomplete', 'Incomplete'), ('complete', 'Complete')],
string="State")
# # @api.one
@api.depends('results')
def _compute_score(self):
for rec in self:
num_questions = self.env['etq.result.question'].search_count(
[('result_id', '=', rec.id)])
correct_questions = self.env['etq.result.question'].search_count(
[('result_id', '=', rec.id), ('correct', '=', True)])
rec.score = str(correct_questions) + "/" + str(
num_questions) + " " + str(
float(float(correct_questions) / float(
num_questions)) * 100) + "%"
# def name_get(self, context=None):
# return self.token
class EtqResultQuestion(models.Model):
_name = "etq.result.question"
_description = "Exam Result Question"
result_id = fields.Many2one('etq.result', string="Result", readonly=True,
ondelete='cascade', )
question_id = fields.Many2one('etq.question', string="Questions",
readonly=True)
question_options = fields.One2many('etq.result.question.option',
'question_id', string="Options",
readonly=True)
correct = fields.Boolean(string="Correct", readonly=True)
question_name = fields.Html(related="question_id.question",
string="Questions")
class EtqResultQuestionOptions(models.Model):
_name = "etq.result.question.option"
_description = "Exam Result Question Option"
question_id = fields.Many2one('etq.result.question_id',
string="Question ID",
readonly=True, ondelete='cascade', )
option_id = fields.Many2one('etq.question.option', string="Options",
readonly=True)
option_name = fields.Char(related="option_id.option", string="Option")
question_options_value = fields.Char(string="Option Value", readonly=True)
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="0">
<record id="group_examp_admin" model="res.groups">
<field name="name">Examp Administrator</field>
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
</record>
</data>
</odoo>
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_etq_exam","access etq.exam","model_etq_exam","base.group_public",1,0,0,0
"access_etq_question","access etq.question","model_etq_question","base.group_public",1,0,0,0
"access_etq_question_option","access etq.question.option","model_etq_question_option","base.group_public",1,0,0,0
"access_etq_question_option_blank","access etq.question.optionblank","model_etq_question_optionblank","base.group_public",1,0,0,0
"access_etq_result","access etq.result","model_etq_result","base.group_public",1,1,0,0
"access_etq_result_question","access etq.result.question","model_etq_result_question","base.group_public",1,1,0,0
"access_etq_result_question_option","access etq.result.question.option","model_etq_result_question_option","base.group_public",1,1,0,0
"access_etq_exam_group_examp_admin","access_group_examp_admin etq.exam","model_etq_exam","group_examp_admin",1,1,1,1
"access_etq_question_group_examp_admin","access_group_examp_admin etq.question","model_etq_question","group_examp_admin",1,1,1,1
"access_etq_question_option_group_examp_admin","access_group_examp_admin etq.question.option","model_etq_question_option","group_examp_admin",1,1,1,1
"access_etq_question_option_blank_group_examp_admin","access_group_examp_admin etq.question.optionblank","model_etq_question_optionblank","group_examp_admin",1,1,1,1
"access_etq_result_group_examp_admin","access_group_examp_admin etq.result","model_etq_result","group_examp_admin",1,0,0,1
"access_etq_result_question_group_examp_admin","access_group_examp_admin etq.result.question","model_etq_result_question","group_examp_admin",1,0,0,1
"access_etq_result_question_option_group_examp_admin","access_group_examp_admin etq.result.question.option","model_etq_result_question_option","group_examp_admin",1,0,0,1
"access_etq_exam_share_group_examp_admin","access_group_examp_admin etq.exam.share","model_etq_exam_share","group_examp_admin",1,0,0,1
<?xml version="1.0"?>
<odoo>
<data noupdate="0">
<!-- <record model="ir.rule" id="tandur_partner_contact_rule">-->
<!-- <field name="name">tandur.partner.contact.rule</field>-->
<!-- <field name="model_id" ref="model_res_partner"/>-->
<!-- <field name="groups" eval="[4,ref('group_tandur_user')]"/>-->
<!-- <field name="domain_force">-->
<!-- ['|','|',('id','=',user.partner_id.id), ('parent_id','=',user.partner_id.id), ('create_uid','=',user.id)]-->
<!-- </field>-->
<!-- <field name="perm_read" eval="True"/>-->
<!-- <field name="perm_create" eval="True"/>-->
<!-- <field name="perm_write" eval="True"/>-->
<!-- <field name="perm_unlink" eval="True"/>-->
<!-- </record>-->
</data>
</odoo>
\ No newline at end of file \ No newline at end of file
<div class="container">
<h2>Description</h2>
Informal Exam / Test / Quiz system<br>
<br>
<section class="oe_container">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan">Create online tests</h2>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="1.jpg">
<img class="oe_picture oe_screenshot" src="2.jpg">
</div>
</div>
<div class="oe_span6">
<p class="oe_mt32">
Create the test.<br/>
<br/>
<b>Instructions</b><br/>
1. Go to Training->Online Tests->Exam<br>
2. Write your questions and click "View Exam"<br>
</p>
</div>
</div>
</section>
</div>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- <record model="ir.actions.act_window" id="etq_exam_share_action">-->
<!-- <field name="name">Share Quiz</field>-->
<!-- <field name="res_model">etq.exam.share</field>-->
<!-- <field name="view_type">form</field>-->
<!-- <field name="view_mode">form</field>-->
<!-- <field name="target">new</field>-->
<!-- <field name="context">{'default_exam_id':active_id}</field>-->
<!-- <field name="help" type="html">-->
<!-- <p class="oe_view_nocontent_create">Share Your Quiz</p>-->
<!-- </field>-->
<!-- </record>-->
<record model="ir.ui.view" id="etq_exam_form_view">
<field name="name">etq exam Form View</field>
<field name="model">etq.exam</field>
<field name="arch" type="xml">
<form>
<header>
<!-- <button name="view_quiz" type="object" string="View Exam"/>-->
<!-- <button type='action' name='pake persen (etq_exam_share_action)d' string="Share Exam"/>-->
</header>
<group>
<field name="name"/>
<field name="show_correct_questions"/>
<field name="fill_mode"/>
<field name="fill_mode_random_number" attrs="{'invisible':[('fill_mode','!=','random')]}"/>
<field name="questions">
<tree>
<field name="question"/>
<field name="question_type"/>
<field name="num_options"/>
<field name="num_correct"/>
</tree>
</field>
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="etq_exam_tree_view">
<field name="name">etq exam Tree View</field>
<field name="model">etq.exam</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="etq_exam_action">
<field name="name">Exams</field>
<field name="res_model">etq.exam</field>
<!-- <field name="view_type">form</field>-->
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">Create an online exam</p>
</field>
</record>
<record model="ir.ui.view" id="etq_question_form_view">
<field name="name">etq question Form View</field>
<field name="model">etq.question</field>
<field name="arch" type="xml">
<form>
<group>
<field name="question"/>
<!-- <field name="question_rendered"/>-->
<field name="question_type"/>
<field name="question_options" attrs="{'invisible':[('question_type','!=','multi_choice')]}"
context="{'question_id':active_id}">
<tree editable="bottom">
<field name="option"/>
<field name="correct"/>
</tree>
</field>
</group>
<div attrs="{'invisible':[('question_type','!=','fill_blank')]}">
pharse questions like this
<br/>
Bob went to the {1} and bought a {2} yesterday
<br/>
the {1} and {2} will get replaced by blank boxes and will be marked as correct if they match the
answers in this list
<br/>
max 9 blank boxes
<field name="question_options_blank" context="{'question_id':active_id}">
<tree editable="bottom">
<field name="answer"/>
</tree>
</field>
</div>
</form>
</field>
</record>
<menuitem id="etq_exams" name="Exams" parent="etq_exam" action="etq_exam_action"
sequence="20"/>
</data>
</odoo>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="etq_exam_share_form_view">
<field name="name">etq exam share Form View</field>
<field name="model">etq.exam.share</field>
<field name="arch" type="xml">
<form>
<group>
<field name="exam_id" invisible="True"/>
<field name="share_type"/>
<field name="partner_ids" attrs="{'invisible': [('share_type','!=','existing_contacts')]}"/>
<field name="email_list" attrs="{'invisible': [('share_type','!=','new_contacts')]}"/>
<field name="email_subject"/>
<field name="email_content"/>
</group>
<footer>
<button name="share_exam" type="object" string="Share Survey"/>
</footer>
</form>
</field>
</record>
</data>
</openerp>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="etq_result_search_view">
<field name="name">etq result Search View</field>
<field name="model">etq.result</field>
<field name="arch" type="xml">
<search>
<field name="state"/>
<filter string="Complete Exams" name="complete_exams" domain="[('state','=','complete')]"/>
<filter string="Incomplete Exams" name="incomplete_exams" domain="[('state','=','complete')]"/>
</search>
</field>
</record>
<record model="ir.ui.view" id="etq_result_form_view">
<field name="name">etq result Form View</field>
<field name="model">etq.result</field>
<field name="arch" type="xml">
<form>
<group>
<field name="create_date" string="Finish Time"/>
<field name="state"/>
<field name="exam_id"/>
<field name="user_id"/>
<field name="score"/>
<field name="results">
<tree>
<field name="question_id"/>
<field name="correct"/>
</tree>
</field>
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="etq_result_question_form_view">
<field name="name">etq result questionForm View</field>
<field name="model">etq.result.question</field>
<field name="arch" type="xml">
<form>
<group>
<field name="question_id"/>
<field name="correct"/>
<field name="question_options">
<tree>
<field name="option_id"/>
<field name="question_options_value"/>
</tree>
</field>
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="etq_result_tree_view">
<field name="name">etq result Tree View</field>
<field name="model">etq.result</field>
<field name="arch" type="xml">
<tree>
<field name="create_date" string="Start Time"/>
<field name="write_date" string="Finish Time"/>
<field name="exam_id"/>
<field name="user_id"/>
<field name="score"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="etq_result_action">
<field name="name">Exam Results</field>
<field name="res_model">etq.result</field>
<!-- <field name="view_type">form</field>-->
<field name="search_view_id" ref="etq_result_search_view"/>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">View Online Exam Results</p>
</field>
</record>
<menuitem id="etq_menu_results" name="Exam Results" parent="etq_exam" action="etq_result_action" sequence="20"/>
</data>
</openerp>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="exam_question_page" name="Exam / Test / Quiz Questions">
<t t-call="website.layout">
<form action="/exam/results" method="post" class="form-horizontal mt32" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="wrap">
<div class="container">
<div class="mt16 mb16">
<h1 class="text-center">
<t t-esc="exam.name"/>
</h1>
</div>
<t t-set="question_index" t-value="0"/>
<t t-foreach="questions" t-as="question_result">
<t t-set="question" t-value="question_result.question_id"/>
<t t-set="question_index" t-value="question_index+1"/>
<div class="form-group">
<div>
<t t-if="question.question_type == 'multi_choice'">
<h2>
<t t-esc="question_index"/>)
<t t-raw="question.question.replace('&lt;p&gt;','').replace('&lt;/p&gt;','')"/>
<t t-if="question.num_correct > 1">
<span>(select<t t-esc="question.num_correct"/>)
</span>
</t>
</h2>
<t t-foreach="question.question_options" t-as="option">
<t t-if="question.num_correct == 1">
<input type="radio" t-attf-name="question#{question.id}"
t-attf-value="#{option.id}" required="True"/>
<t t-esc="option.option"/>
<br/>
</t>
<t t-if="question.num_correct > 1">
<input type="checkbox"
t-attf-name="question#{question.id}option#{option.id}"
t-attf-value="#{option.id}"/>
<t t-esc="option.option"/>
<br/>
</t>
</t>
</t>
<t t-if="question.question_type == 'fill_blank'">
<script>
window.onload = function() {
$('input[type="text"]').keydown(resizeInput)
};
function resizeInput() {
$(this).attr('size', $(this).val().length);
}
</script>
<h2>
<t t-esc="question_index"/>)
<t t-raw="question.question_rendered"/>
</h2>
</t>
</div>
</div>
</t>
<div class="form-group">
<div class="col-md-7 col-sm-8">
<input type="hidden" name="token" t-attf-value="#{token}"/>
<button class="btn btn-primary btn-lg">Finish</button>
</div>
</div>
</div>
</div>
</form>
</t>
</template>
<template id="exam_results" name="Exam / Test / Quiz Results">
<t t-call="website.layout">
<div class="wrap">
<div class="container">
<div class="mt16 mb16">
<h1 class="text-center">Results</h1>
</div>
<div class="mt16 mb16">
<h2 class="text-center text-center">
<t t-esc="correct_count"/>
/
<t t-esc="question_count"/>
<br/>
<t t-esc="percent"/>%
</h2>
<t t-if="exam_result.exam_id.show_correct_questions == True">
<style>
td, th {
padding: 5px;
}
</style>
<table>
<tr>
<th>Question</th>
<th>Correct</th>
</tr>
<t t-foreach="exam_result.results" t-as="question_result">
<tr>
<td>
<t t-esc="question_result.question.question"/>
</td>
<td>
<t t-if="question_result.correct == True">
<span style="color:green;">Correct</span>
</t>
<t t-if="question_result.correct == False">
<span style="color:red;">Incorrect</span>
</t>
</td>
</tr>
</t>
</table>
</t>
</div>
</div>
</div>
</t>
</template>
</data>
</openerp>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem id="training" name="Training" active="True" sequence="90"/>
<menuitem id="etq_exam" name="Online Tests" parent="training" sequence="10"/>
</odoo>
\ No newline at end of file \ No newline at end of file
=======
School
=======
This module was written to extend the functionality of school to support school management and allow you to get a functionality of school management.
Installation
============
To install this module, you need to:
install 'hr', 'crm', 'account', module
Configuration
=============
To configure this module, you need to:
have a school management functionality.
Usage
=====
To use this module, you need to:
go to apps, then install module to apply this functionality.
Try me on Runbot
Known issues / Roadmap
Bug Tracker
===========
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed feedback here.
=======
Credits
=======
Contributors
============
Serpent Consulting Services PVT. LTD. <http://serpentcs.com>
Maintainer
===========
Serpent Consulting Services PVT. LTD.
This module is maintained by the SerpentCS.
To contribute to this module, please visit http://serpentcs.com.
# See LICENSE file for full copyright and licensing details.
# ----------------------------------------------------------
# A Module for School Management System
# ----------------------------------------------------------
from . import models
from . import wizard
# See LICENSE file for full copyright and licensing details.
{
'name': 'School',
'version': '14.0.1.0.0',
'author': 'Serpent Consulting Services Pvt. Ltd.',
'website': 'http://www.serpentcs.com',
'category': 'School Management',
'license': "AGPL-3",
'complexity': 'easy',
'Summary': 'A Module For School Management',
'images': ['static/description/EMS.jpg'],
'depends': ['hr', 'crm', 'account'],
'data': ['security/school_security.xml',
'security/ir.model.access.csv',
'data/student_sequence.xml',
'wizard/terminate_reason_view.xml',
'wizard/wiz_send_email_view.xml',
'views/student_view.xml',
'views/school_view.xml',
'views/teacher_view.xml',
'views/parent_view.xml',
'wizard/assign_roll_no_wizard.xml',
'wizard/move_standards_view.xml',
'report/report_view.xml',
'report/identity_card.xml',
'views/template_view.xml'],
'demo': ['demo/school_demo.xml'],
'installable': True,
'application': True
}
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Sequences For student.code (Student Code) -->
<record id="seq_student_code" model="ir.sequence">
<field name="name">Student code</field>
<field name="code">student.code</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<!-- Sequences For student.registration (Registration Code) -->
<record id="seq_student_reg" model="ir.sequence">
<field name="name">Student registration code</field>
<field name="code">student.registration</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<!-- Sequences For student.student (Personal Identification Number) -->
<record id="seq_student_student" model="ir.sequence">
<field name="name">Student</field>
<field name="code">student.student</field>
<field name="prefix">%(year)s/%(month)s/</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<!-- Sequences For student.document (Student Documents) -->
<record id="seq_student_document" model="ir.sequence">
<field name="name">Document</field>
<field name="code">student.document</field>
<field name="prefix">F</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<!-- Sequences For document.type (Document Type) -->
<record id="seq_student_sequence" model="ir.sequence">
<field name="name">sequence</field>
<field name="code">document.type</field>
<field name="padding">1</field>
<field name="company_id" eval="False"/>
</record>
</data>
</odoo>
# See LICENSE file for full copyright and licensing details.
# ----------------------------------------------------------
# A Module to School Management System
# ----------------------------------------------------------
from . import school
from . import student
from . import teacher
from . import parent
from . import res_users
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class ParentRelation(models.Model):
'''Defining a Parent relation with child.'''
_name = "parent.relation"
_description = "Parent-child relation information"
name = fields.Char("Relation name", required=True,
help='Parent relation with student')
class SchoolParent(models.Model):
'''Defining a Teacher information.'''
_name = 'school.parent'
_description = 'Parent Information'
partner_id = fields.Many2one('res.partner', 'User ID', ondelete="cascade",
delegate=True, required=True,
help='Partner which is user over here')
relation_id = fields.Many2one('parent.relation', 'Relation with Child',
help='Parent relation with child')
student_id = fields.Many2many('student.student', 'students_parents_rel',
'students_parent_id', 'student_id',
'Children',
help='Student of the following parent')
standard_id = fields.Many2many('school.standard',
'school_standard_parent_rel',
'class_parent_id', 'class_id',
'Academic Class',
help='''Class of the student
of following parent''')
stand_id = fields.Many2many('standard.standard',
'standard_standard_parent_rel',
'standard_parent_id', 'standard_id',
'Academic Standard',
help='''Standard of the student
of following parent''')
teacher_id = fields.Many2one('school.teacher', 'Teacher',
related="standard_id.user_id", store=True,
help='Teacher of a student')
@api.onchange('student_id')
def onchange_student_id(self):
"""Onchange Method for Student."""
standard_ids = [student.standard_id.id
for student in self.student_id]
if standard_ids:
stand_ids = [student.standard_id.standard_id.id
for student in self.student_id]
self.standard_id = [(6, 0, standard_ids)]
self.stand_id = [(6, 0, stand_ids)]
@api.model
def create(self, vals):
"""Inherited create method to assign values in
the users record to maintain the delegation"""
parent_rec = super(SchoolParent, self).create(vals)
parent_grp_id = self.env.ref('school.group_school_parent')
emp_grp = self.env.ref('base.group_user')
parent_group_ids = [emp_grp.id, parent_grp_id.id]
user_vals = {'name': parent_rec.name,
'login': parent_rec.email,
'email': parent_rec.email,
'partner_id': parent_rec.partner_id.id,
'groups_id': [(6, 0, parent_group_ids)]
}
self.env['res.users'].create(user_vals)
return parent_rec
@api.onchange('state_id')
def onchange_state(self):
"""Onchange Method for State."""
if self.state_id:
self.country_id = self.state_id.country_id.id or False
# See LICENSE file for full copyright and licensing details.
from odoo import api, models
class ResUsers(models.Model):
_inherit = "res.users"
@api.model
def create(self, vals):
"""Inherit Method to create user of group teacher or parent."""
vals.update({'employee_ids': False})
user_rec = super(ResUsers, self).create(vals)
if self._context.get('teacher_create', False):
teacher_grp_id = self.env.ref('school.group_school_teacher')
user_base_grp = self.env.ref('base.group_user')
contact_create = self.env.ref('base.group_partner_manager')
teacher_group_ids = [user_base_grp.id, teacher_grp_id.id,
contact_create.id]
user_rec.write({'groups_id': [(6, 0, teacher_group_ids)],
'company_id': self._context.get('school_id'),
'company_ids': [(4, self._context.get('school_id'))
]})
return user_rec
# See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class SchoolTeacher(models.Model):
'''Defining a Teacher information.'''
_name = 'school.teacher'
_description = 'Teacher Information'
_inherit = ['mail.thread', 'mail.activity.mixin']
employee_id = fields.Many2one('hr.employee', 'Employee ID',
ondelete="cascade",
delegate=True, required=True,
help='Enter related employee')
standard_id = fields.Many2one('school.standard',
"Responsibility of Academic Class",
help="Standard for which the teacher\
responsible for.")
stand_id = fields.Many2one('standard.standard', "Course",
related="standard_id.standard_id", store=True,
help='''Select standard which are
assigned to teacher''')
subject_id = fields.Many2many('subject.subject', 'subject_teacher_rel',
'teacher_id', 'subject_id',
'Course-Subjects',
help='Select subject of teacher')
school_id = fields.Many2one('school.school', "Campus",
help='Select school')
category_ids = fields.Many2many('hr.employee.category',
'teacher_category_rel', 'emp_id',
'categ_id', 'Tags',
help='Select employee category')
department_id = fields.Many2one('hr.department', 'Department',
help='Select department')
is_parent = fields.Boolean('Is Parent',
help='Select this if it parent')
stu_parent_id = fields.Many2one('school.parent', 'Related Parent',
help='Enter student parent')
student_id = fields.Many2many('student.student',
'students_teachers_parent_rel',
'teacher_id', 'student_id',
'Children', help='Select student')
phone_numbers = fields.Char("Phone Number", help='Student PH no')
@api.onchange('standard_id')
def _onchange_standard_id(self):
for rec in self:
if rec.standard_id:
rec.school_id = rec.standard_id.school_id.id
@api.onchange('is_parent')
def _onchange_isparent(self):
"""Onchange method for is parent"""
if self.is_parent:
self.stu_parent_id = False
self.student_id = False
@api.onchange('stu_parent_id')
def _onchangestudent_parent(self):
"""Onchange method for student parent records"""
stud_list = []
if self.stu_parent_id and self.stu_parent_id.student_id:
for student in self.stu_parent_id.student_id:
stud_list.append(student.id)
self.student_id = [(6, 0, stud_list)]
@api.model
def create(self, vals):
"""Inherited create method to assign value to users for delegation"""
teacher_id = super(SchoolTeacher, self).create(vals)
user_obj = self.env['res.users']
user_vals = {'name': teacher_id.name,
'login': teacher_id.work_email,
'email': teacher_id.work_email,
}
ctx_vals = {'teacher_create': True,
'school_id': teacher_id.school_id.company_id.id}
user_rec = user_obj.with_context(ctx_vals).create(user_vals)
teacher_id.employee_id.write({'user_id': user_rec.id})
# if vals.get('is_parent'):
# self.parent_crt(teacher_id)
return teacher_id
# Removing this code because of issue faced due to email id of the
# user is same for parent and Teacher, and system will not allow it.
# now user shuld create Parent record first and then select it in
# related parent in Teacher Profile. - Anu Patel (24/03/2021)
# def parent_crt(self, manager_id):
# """Method to create parent record based on parent field"""
# stu_parent = []
# if manager_id.stu_parent_id:
# stu_parent = manager_id.stu_parent_id
# if not stu_parent:
# emp_user = manager_id.employee_id
# students = [stu.id for stu in manager_id.student_id]
# parent_vals = {'name': manager_id.name,
# 'email': emp_user.work_email,
# 'user_ids': [(6, 0, [emp_user.user_id.id])],
# 'partner_id': emp_user.user_id.partner_id.id,
# 'student_id': [(6, 0, students)]}
# stu_parent = self.env['school.parent'].with_context().create(parent_vals)
# manager_id.write({'stu_parent_id': stu_parent.id})
# user = stu_parent.user_ids
# user_rec = user[0]
# parent_grp_id = self.env.ref('school.group_school_parent')
# groups = parent_grp_id
# if user_rec.groups_id:
# groups = user_rec.groups_id
# groups += parent_grp_id
# group_ids = [group.id for group in groups]
# user_rec.write({'groups_id': [(6, 0, group_ids)]})
def write(self, vals):
"""Inherited write method to assign groups based on parent field"""
# if vals.get('is_parent'):
# self.parent_crt(self)
if vals.get('student_id'):
self.stu_parent_id.write({'student_id': vals.get('student_id')})
if not vals.get('is_parent'):
user_rec = self.employee_id.user_id
ir_obj = self.env['ir.model.data']
parent_grp_id = ir_obj.get_object('school', 'group_school_parent')
groups = parent_grp_id
if user_rec.groups_id:
groups = user_rec.groups_id
groups -= parent_grp_id
group_ids = [group.id for group in groups]
user_rec.write({'groups_id': [(6, 0, group_ids)]})
return super(SchoolTeacher, self).write(vals)
@api.onchange('address_id')
def onchange_address_id(self):
"""Onchange method for address."""
self.work_phone = self.address_id.phone or False,
self.mobile_phone = self.address_id.mobile or False
@api.onchange('department_id')
def onchange_department_id(self):
"""Onchange method for deepartment."""
self.parent_id = (self.department_id and
self.department_id.manager_id and
self.department_id.manager_id.id) or False
@api.onchange('user_id')
def onchange_user(self):
"""Onchange method for user."""
if self.user_id:
self.name = self.name or self.user_id.name
self.work_email = self.user_id.email
self.image = self.image or self.user_id.image
@api.onchange('school_id')
def onchange_school(self):
"""Onchange method for school."""
self.address_id = self.school_id.company_id.partner_id.id or \
False
self.mobile_phone = self.school_id.company_id.partner_id.mobile or \
False
self.work_location = self.school_id.company_id.partner_id.city or \
False
self.work_email = self.school_id.company_id.partner_id.email or False
phone = self.school_id.company_id.partner_id.phone or False
self.work_phone = phone or False
self.phone_numbers = phone or False
phone = self.school_id.company_id.partner_id.phone or False
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="identity_card">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="web.external_layout">
<div class="page" style="height: 2px;">
<div class="oe_structure"/>
<br/>
<br/>
<br/>
<br/>
<br/>
<t t-foreach="o" t-as="student">
<br/><br/><br/>
<table width="25%" height="50px" style="border: 3px solid black;">
<tr>
<td width="100%" align="center" height="30">
<strong>
<span t-field="student.school_id.name" />
</strong>
</td>
</tr>
<tr>
<td align="center">
<img t-if="student.photo" t-att-src="'data:image/png;base64,%s' % to_text(student.photo)"
style="height:120px;width=120px" />
</td>
</tr>
<tr>
<td height="10px"></td>
</tr>
<tr>
<td align="center" height="30px">
<strong>
<span t-field="student.name" />
</strong>
<strong>
<span t-field="student.middle" />
</strong>
<strong>
<span t-field="student.last" />
</strong>
</td>
</tr>
<tr>
<td height="130">
<table width="100%">
<tr>
<td style="font-family: 'Helvetica';padding-left:20px;">
<strong>Roll No.</strong>
</td>
<td>
<strong>: </strong>
</td>
<td>
<span t-field="student.roll_no" />
</td>
</tr>
<tr>
<td style="font-family: 'Helvetica';padding-left:20px;">
<strong>Standard</strong>
</td>
<td>
<strong>: </strong>
</td>
<td>
<span t-field="student.standard_id.standard_id.name"/>
</td>
</tr>
<tr>
<td style="font-family: 'Helvetica';padding-left:20px;">
<strong>Division</strong>
</td>
<td>
<strong>: </strong>
</td>
<td>
<span t-field="student.standard_id.division_id.name"/>
</td>
</tr>
<tr>
<td style="font-family: 'Helvetica';padding-left:20px;">
<strong>Medium</strong>
</td>
<td>
<strong>: </strong>
</td>
<td>
<span t-field="student.medium_id.name" />
</td>
</tr>
<tr>
<td style="font-family: 'Helvetica';padding-left:20px;">
<strong>BirthDate</strong>
</td>
<td>
<strong>: </strong>
</td>
<td>
<span t-field="student.date_of_birth" />
</td>
</tr>
<tr>
<td style="font-family: 'Helvetica';padding-left:20px;">
<strong>Blood Group</strong>
</td>
<td>
<strong>: </strong>
</td>
<td>
<span t-field="student.blood_group" />
</td>
</tr>
</table>
</td>
</tr>
</table>
</t>
</div>
</t>
</t>
</t>
</template>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="report_student_student" model="ir.actions.report">
<field name="name">Identity Card</field>
<field name="model">student.student</field>
<field name="binding_model_id" ref="model_student_student"/>
<field name="report_type">qweb-pdf</field>
<field name="report_name">school.identity_card</field>
<field name="report_file">school.identity_card</field>
<field name="binding_type">report</field>
<field name="groups_id" eval="[(4, ref('school.group_school_administration')),
(4, ref('school.group_school_teacher')),
(4, ref('school.group_school_student'))]"/>
</record>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="module_category_school" model="ir.module.category">
<field name="name">School Management</field>
<field name="sequence">22</field>
</record>
<record id="group_school_administration" model="res.groups">
<field name="name">School Administrator</field>
<field name="category_id" ref="module_category_school"/>
<field name="users" eval="[(4, ref('base.user_root')),(4, ref('base.user_admin'))]"/>
</record>
<record id="group_school_teacher" model="res.groups">
<field name="name">School Teacher</field>
<field name="category_id" ref="module_category_school"/>
</record>
<record id="group_school_student" model="res.groups">
<field name="name">School Student</field>
<field name="category_id" ref="module_category_school"/>
</record>
<record id="group_school_parent" model="res.groups">
<field name="name">Student Parent</field>
<field name="category_id" ref="module_category_school"/>
</record>
<record id="group_is_admission" model="res.groups">
<field name="name">In Admission</field>
<field name="category_id" ref="module_category_school"/>
</record>
<!-- Rule For Creating Personal School Record As A Teacher, Student & Parent-->
<record id="rule_personal_school_record" model="ir.rule">
<field name="name">Rule Personal School Record</field>
<field name="model_id" ref="model_school_school"/>
<field name="domain_force">['|','|',('company_id.child_ids', 'child_of', [user.company_id.id]),('company_id', 'child_of', [user.company_id.id]),('company_id', '=', False)]</field>
<field name="groups" eval="[(4, ref('group_school_teacher')),(4, ref('group_school_student')),(4, ref('group_school_parent'))]"/>
</record>
<!-- Rule For Student Profile Record As A Student -->
<record id="rule_student_profile_record_as_student" model="ir.rule">
<field name="name">Rule Student Profile Record As A Student</field>
<field name="model_id" ref="model_student_student"/>
<field name="global" eval="True"/>
<field name="domain_force">[('user_id','=',user.id)]</field>
<field name="groups" eval="[(4, ref('group_school_student'))]"/>
</record>
<!-- Rule For Student Profile Record As An Administrator -->
<record id="rule_student_profile_record_as_admin" model="ir.rule">
<field name="name">Rule Student Profile Record As An Administrator</field>
<field name="model_id" ref="model_student_student"/>
<field name="global" eval="True"/>
<field name="domain_force"> ['|','|',('company_id.child_ids','child_of',[user.company_id.id]),('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field>
<field name="groups" eval="[(4, ref('group_school_administration'))]"/>
</record>
<!-- Rule For Student Profile Record As A Teacher -->
<record id="rule_student_profile_record_as_teacher" model="ir.rule">
<field name="name">Rule Student Profile Record As A Teacher</field>
<field name="model_id" ref="model_student_student"/>
<field name="global" eval="True"/>
<field name="domain_force">[('company_id','=',user.company_id.id)]</field>
<field name="groups" eval="[(4, ref('group_school_teacher'))]"/>
</record>
<!-- Rule For Student Profile Record As A Parent -->
<!-- <record id="rule_student_profile_record_as_parent" model="ir.rule"> -->
<!-- <field name="name">Rule Student Profile Record As A Parent</field> -->
<!-- <field name="model_id" ref="model_student_student"/> -->
<!-- <field name="global" eval="True"/> -->
<!-- <field name="domain_force"> [('id','in', user.partner_id.student_ids.ids)]</field> -->
<!-- <field name="groups" eval="[(4, ref('group_school_parent'))]"/> -->
<!-- </record> -->
<record id="rule_student_profile_record_as_parent" model="ir.rule">
<field name="name">Rule Student Profile Record As A Parent</field>
<field name="model_id" ref="model_student_student"/>
<field name="global" eval="True"/>
<field name="domain_force"> [('parent_id.partner_id','=',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('group_school_parent'))]"/>
</record>
<!-- Rule For School Standard Record As An Administrator -->
<record id="rule_school_standard_record_as_admin" model="ir.rule">
<field name="name">Rule School Standard Record As An Administrator</field>
<field name="model_id" ref="model_school_standard"/>
<field name="global" eval="True"/>
<field name="domain_force"> ['|','|',('cmp_id.child_ids','child_of',[user.company_id.id]),('cmp_id','child_of',[user.company_id.id]),('cmp_id','=',False)]</field>
<field name="groups" eval="[(4, ref('group_school_administration'))]"/>
</record>
<!-- Record Rule teacher can see standards related to school -->
<record id="rule_school_standard_teacher" model="ir.rule">
<field name="name">Teacher School Standard Record Rule</field>
<field name="model_id" ref="model_school_standard"/>
<field name="global" eval="True"/>
<field name="domain_force">[('school_id.company_id','=',user.company_id.id)]</field>
<field name="groups" eval="[(4, ref('group_school_teacher'))]"/>
</record>
<!-- Rule For News Update Record As A Student & Teacher -->
<record id="rule_student_news_update_record" model="ir.rule">
<field name="name">Rule News Update Record</field>
<field name="model_id" ref="model_student_news"/>
<field name="global" eval="True"/>
<field name="domain_force">[('user_ids.id','=',user.id)]</field>
<field name="groups" eval="[(4, ref('school.group_school_student')),(4, ref('school.group_school_teacher'))]"/>
</record>
<!-- Record Rule parents can see reminder of own child -->
<record id="parents_reminder_record_rule" model="ir.rule">
<field name="name">Parents Reminder Record Rule</field>
<field name="model_id" ref="model_student_reminder"/>
<field name="global" eval="True"/>
<field name="domain_force">[('stu_id.parent_id.partner_id','=',user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('school.group_school_parent'))]"/>
</record>
<!-- Record Rule student can see reminder of their own -->
<record id="student_reminder_record_rule" model="ir.rule">
<field name="name">Student Remainder Record Rule</field>
<field name="model_id" ref="model_student_reminder"/>
<field name="global" eval="True"/>
<field name="domain_force">[('stu_id.user_id','=',user.id)]</field>
<field name="groups" eval="[(4, ref('school.group_school_student'))]"/>
</record>
<!-- Rule For School Teacher -->
<!-- <record id="rule_school_teacher_own" model="ir.rule"> -->
<!-- <field name="name">Rule School Teacher Self</field> -->
<!-- <field name="model_id" ref="hr.model_hr_employee"/> -->
<!-- <field name="global" eval="True"/> -->
<!-- <field name="domain_force"> [('user_id','=',user.id)]</field> -->
<!-- <field name="groups" eval="[(4, ref('school.group_school_teacher'))]"/> -->
<!-- </record> -->
<record id="rule_personal_school_teacher" model="ir.rule">
<field name="name">Rule Personal teacher Record</field>
<field name="model_id" ref="model_school_teacher"/>
<field name="domain_force">[('employee_id.user_id.id', '=', user.id)]</field>
<field name="groups" eval="[(4, ref('group_school_teacher'))]"/>
</record>
<!-- Rule For Parent Profile Record As A Parent -->
<record id="rule_school_parents" model="ir.rule">
<field name="name">Rule Parent Profile Record As A Parent</field>
<field name="model_id" ref="model_school_parent"/>
<field name="global" eval="True"/>
<field name="domain_force"> [('partner_id','=', user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('school.group_school_parent'))]"/>
</record>
<!-- Record Rule student can see own parent -->
<record id="rule_stud_parent" model="ir.rule">
<field name="name">Record rule student can see own parent</field>
<field name="model_id" ref="model_school_parent"/>
<field name="global" eval="True"/>
<field name="domain_force"> [('student_id.user_id','=', user.id)]</field>
<field name="groups" eval="[(4, ref('school.group_school_student'))]"/>
</record>
<!-- Rule For Student Profile Record in Adminssion -->
<record id="rule_student_profile_record_as_student_in_admisssion" model="ir.rule">
<field name="name">Rule Student Profile Record As A Student for in Adminssion </field>
<field name="model_id" ref="model_student_student"/>
<field name="global" eval="True"/>
<field name="domain_force">[('user_id','=',user.id)]</field>
<field name="groups" eval="[(4, ref('group_is_admission'))]"/>
</record>
</data>
</odoo>
.o_column_quick_create {
display:none
}
.o_column_delete {
display:none !important;
}
# See LICENSE file for full copyright and licensing details.
# ----------------------------------------------------------
# A Module to School Management System
# ----------------------------------------------------------
from . import test_school
# See LICENSE file for full copyright and licensing details.
from odoo.tests import common
class TestSchool(common.TransactionCase):
def setUp(self):
super(TestSchool, self).setUp()
self.student_student_obj = self.env['student.student']
self.teacher_obj = self.env['school.teacher']
self.parent_obj = self.env['school.parent']
self.school_school_obj = self.env['school.school']
self.school_standard_obj = self.env['school.standard']
self.res_company_obj = self.env['res.company']
self.assign_roll_obj = self.env['assign.roll.no']
self.school_id = self.env.ref('school.demo_school_1')
self.standard_medium = self.env.ref('school.demo_standard_medium_1')
self.year = self.env.ref('school.demo_academic_year_2')
self.currency_id = self.env.ref('base.INR')
self.sch = self.env.ref('school.demo_school_1')
self.country_id = self.env.ref('base.in')
self.std = self.env.ref('school.demo_standard_standard_1')
self.state_id = self.env.ref('base.state_in_gj')
self.subject1 = self.env.ref('school.demo_subject_subject_1')
self.subject2 = self.env.ref('school.demo_subject_subject_2')
self.student_student = self.env.ref('school.demo_student_student_2')
self.student_done = self.env.ref('school.demo_student_student_6')
self.parent = self.env.ref('school.demo_student_parent_1')
student_list = [self.student_done.id]
self.student_student._compute_student_age()
self.student_student.check_age()
self.student_student.admission_done()
self.student_student.set_alumni()
self.parent.student_id = [(6, 0, student_list)]
# Create academic Year
self.academic_year_obj = self.env['academic.year']
self.academic_year = self.academic_year_obj.\
create({'sequence': 7,
'code': '2012',
'name': '2012 Year',
'date_start': '2012-01-01',
'date_stop': '2012-12-31'
})
self.academic_year._check_academic_year()
self.academic_month_obj = self.env['academic.month']
# Academic month created
self.academic_month = self.academic_month_obj.\
create({'name': 'May',
'code': 'may',
'date_start': '2012-05-01',
'date_stop': '2012-05-31',
'year_id': self.academic_year.id
})
self.academic_month._check_duration()
self.academic_month._check_year_limit()
self.assign_roll_no = self.assign_roll_obj.\
create({'standard_id': self.std.id,
'medium_id': self.standard_medium.id
})
self.assign_roll_no.assign_rollno()
def test_school(self):
self.assertEqual(self.student_student.school_id,
self.student_student.standard_id.school_id)
<?xml version="1.0" ?>
<odoo>
<data>
<!-- search View Of Parent's Profiles -->
<record id="view_school_parent_search" model="ir.ui.view">
<field name="name">school.parent.search</field>
<field name="model">school.parent</field>
<field name="arch" type="xml">
<search string="Search Parent">
<field name="name" filter_domain="['|','|',('display_name','ilike',self),('ref','=',self),('email','ilike',self)]"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
</search>
</field>
</record>
<!-- tree View Of Parent's Profiles -->
<record id="view_school_parent_tree" model="ir.ui.view">
<field name="name">school.parent.tree</field>
<field name="model">school.parent</field>
<field name="arch" type="xml">
<tree string="Parents">
<field name="name"/>
<field name="relation_id"/>
<field name="phone"/>
<field name="email"/>
<field name="city"/>
<field name="country_id"/>
</tree>
</field>
</record>
<!-- Form View Of Parent's Profiles -->
<record id="view_school_parent_form" model="ir.ui.view">
<field name="name">school.parent.form</field>
<field name="model">school.parent</field>
<field name="arch" type="xml">
<form string="Parents">
<sheet>
<field name="type" invisible="1"/>
<!-- <field name="image" widget="image" class="oe_avatar" options="{&quot;preview_image&quot;: &quot;image_medium&quot;, &quot;size&quot;: [90, 90]}"/> -->
<div class="oe_title">
<h1>
<field name="name" default_focus="1" placeholder="Name" attrs="{'required' : [('type', '=', 'contact')]}"/>
</h1>
</div>
<div>
<label for="relation_id"/>
<field name="relation_id"/>
</div>
<group>
<group string="Postal Address" name="postal_address">
<label for="street" string="Address"/>
<div class="o_address_format">
<field name="street" placeholder="Street..." class="o_address_street"/>
<field name="street2" placeholder="Street 2..." class="o_address_street"/>
<field name="city" placeholder="City" class="o_address_city"/>
<field name="state_id" class="o_address_state" placeholder="State"
options="{&quot;no_open&quot;: True}"
context="{'country_id': country_id, 'zip': zip}"/>
<field name="zip" placeholder="ZIP" class="o_address_zip"/>
<field name="country_id" placeholder="Country" class="o_address_country"
options="{&quot;no_open&quot;: True, &quot;no_create&quot;: True}"/>
</div>
</group>
<group string="Communication" name="communication">
<field name="phone" widget="phone"/>
<field name="mobile" widget="phone"/>
<field name="user_ids" invisible="1"/>
<field name="email" widget="email" required="1"/>
<field name="title" options="{&quot;no_open&quot;: True}"/>
<field name="lang"/>
<field name="category_id" widget="many2many_tags" placeholder="Tags..."/>
</group>
</group>
<notebook>
<page name="children" string="Children">
<field name="student_id" colspan="4" domain="[('state','=','done')]"/>
</page>
<page name="internal_notes" string="Internal Notes">
<field name="comment" placeholder="Internal note..."/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- Action View Of school parent-->
<record id="action_school_parent_form" model="ir.actions.act_window">
<field name="name">Parent Profile</field>
<field name="res_model">school.parent</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_res_partner_form" name="Parents" parent="menu_students_parents"
action="action_school_parent_form" sequence="33"
groups="school.group_school_administration,school.group_school_student,school.group_school_teacher,school.group_school_parent"/>
</data>
</odoo>
<?xml version="1.0" ?>
<odoo>
<data>
<!-- search View Of Teahcer's Profiles -->
<record id="view_school_teacher_search" model="ir.ui.view">
<field name="name">school.teacher.search</field>
<field name="model">school.teacher</field>
<field name="arch" type="xml">
<search string="Employees">
<field name="name" string="Employees" filter_domain="['|',('work_email','ilike',self),('name','ilike',self)]"/>
<field name="department_id"/>
<field name="category_ids" groups="hr.group_hr_user"/>
<field name="job_id"/>
<filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
<group expand="0" string="Group By">
<filter name="manager" string="Manager" domain="[]" context="{'group_by':'parent_id'}"/>
<filter name="coach" string="Coach" domain="[]" context="{'group_by':'coach_id'}"/>
<filter name="department" string="Department" domain="[]" context="{'group_by':'department_id'}"/>
<filter name="job" string="Job" domain="[]" context="{'group_by':'job_id'}"/>
<filter name="company" string="Company" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
</group>
</search>
</field>
</record>
<!-- tree View Of Teahcer's Profiles -->
<record id="view_school_teacher_tree" model="ir.ui.view">
<field name="name">school.teacher.tree</field>
<field name="model">school.teacher</field>
<field name="arch" type="xml">
<tree string="Faculty" decoration-bf="message_needaction==True">
<field name="name"/>
<field name="work_phone" invisible="1"/>
<field name="phone_numbers"/>
<field name="work_email"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="department_id"/>
<field name="job_id"/>
<field name="parent_id"/>
<field name="coach_id" invisible="1"/>
<field name="message_needaction" invisible="1"/>
</tree>
</field>
</record>
<!-- Form View Of Teahcer's Profiles -->
<record id="view_school_teacher_form" model="ir.ui.view">
<field name="name">school.teacher.form</field>
<field name="model">school.teacher</field>
<field name="arch" type="xml">
<form string="Faculty">
<sheet>
<!-- <field name="image" widget="image" class="oe_avatar" options="{&quot;preview_image&quot;:&quot;image_medium&quot;}"/>
--> <div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name" placeholder="Teacher's Name" required='1'/>
</h1>
</div>
<field name="category_ids" widget="many2many_tags" placeholder="e.g. Part Time" groups="hr.group_hr_user"/>
<group>
<field name="standard_id" widget="selection"/>
<!-- <field name="standard_ids" required="1" widget="many2many_tags"/> -->
<field name="subject_id" required="1" widget="many2many_tags" options="{'no_create': True}"/>
<field name="school_id" widget="selection"/>
</group>
<group>
<field name="is_parent" widget="boolean_toggle"/>
<field name='stu_parent_id'
attrs="{'invisible':[('is_parent','=',False)],'required': [('is_parent','!=',False)]}"/>
</group>
<notebook>
<page name="public" string="Public Information">
<group>
<group string="Contact Information">
<field name="address_id" context="{'show_address': 1}" options="{&quot;always_reload&quot;: True, &quot;highlight_first_line&quot;: True}" string="Work Address"/>
<field name="mobile_phone" />
<field name="work_location" />
<field name="work_email" widget="email" required="1"/>
<field name="work_phone" invisible="1"/>
<field name="phone_numbers"/>
</group>
<group string="Position">
<field name="department_id"/>
<field name="job_id"/>
<field name="parent_id"/>
<field name="coach_id"/>
</group>
</group>
<field name="notes" placeholder="Other Information ..." colspan="4"/>
</page>
<page string="Personal Information" groups="hr.group_hr_user">
<group>
<group string="Citizenship &amp; Other Information">
<field name="country_id" options="{&quot;no_open&quot;: True, &quot;no_create&quot;: True}"/>
<field name="identification_id" groups="hr.group_hr_user"/>
<field name="passport_id" groups="hr.group_hr_user"/>
<field name="bank_account_id"/>
</group>
<group string="Contact Information">
<field name="address_home_id" context="{'show_address': 1}" options="{&quot;always_reload&quot;: True, &quot;highlight_first_line&quot;: True}"/>
</group>
<group string="Status">
<field name="gender"/>
<field name="marital"/>
</group>
<group string="Birth">
<field name="birthday"/>
</group>
</group>
</page>
<page string="Children" attrs="{'invisible': [('is_parent','=', False)]}">
<field name="student_id" domain="[('state', '=', 'done')]"/>
</page>
<page string="HR Settings" groups="hr.group_hr_user" invisible="1">
<group>
<group string="Status" name="active_group">
<field name="company_id" groups="base.group_multi_company"/>
<field name="user_id" string="Related User" context="{'default_groups_ref': ['base.group_user']}"/>
</group>
</group>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<!-- Action View Of school teacher-->
<record id="action_school_teacher_form" model="ir.actions.act_window">
<field name="name">Teacher Profile</field>
<field name="res_model">school.teacher</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="teacher_profile_menu" name="Teachers" action="action_school_teacher_form"
parent="menu_students_parents" sequence="32"
groups="school.group_school_administration,school.group_school_teacher"/>
</data>
</odoo>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="assets_backend" name="school assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/school/static/src/scss/schoolcss.scss"/>
</xpath>
</template>
</data>
</odoo>
# See LICENSE file for full copyright and licensing details.
from . import assign_roll_no
from . import move_standards
from . import wiz_send_email
from . import teriminate_reason
# See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class AssignRollNo(models.TransientModel):
'''designed for assigning roll number to a student'''
_name = 'assign.roll.no'
_description = 'Assign Roll Number'
standard_id = fields.Many2one('school.standard', 'Class', required=True)
medium_id = fields.Many2one('standard.medium', 'Medium', required=True)
def assign_rollno(self):
'''Method to assign roll no to students'''
student_obj = self.env['student.student']
# Search Student
for rec in self:
student_ids = student_obj.search([
('standard_id', '=', rec.standard_id.id),
('medium_id', '=', rec.medium_id.id)],
order="name")
# Assign roll no according to name.
number = 1
for student in student_ids:
number += 1
student.write({'roll_no': number})
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Assign Roll Number Wizard Form View -->
<record id="view_assign_roll_no_form" model="ir.ui.view">
<field name="name">assign.roll.no.form</field>
<field name="model">assign.roll.no</field>
<field name="arch" type="xml">
<form string="Assigning Roll Number">
<separator string="Assign Roll Number" colspan="4"/>
<group colspan="4" col="6">
<field name="standard_id" widget="selection" />
<field name="medium_id" widget="selection" />
</group>
<footer>
<button class="btn btn-sm btn-default fa fa-ban" special="cancel" string="Close"/>
<button class="btn btn-sm btn-default fa fa-plus" name="assign_rollno" string="Finish" type="object"/>
</footer>
</form>
</field>
</record>
<!-- Action Of Form Views Of Assign Roll Number -->
<record id="action_assign_roll_no_form" model="ir.actions.act_window">
<field name="name">Assign Roll Number</field>
<field name="res_model">assign.roll.no</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_assign_roll_no_form" />
<field name="target">new</field>
</record>
<!-- MenuItem For Configurations->Move Classes -->
<menuitem id="menu_assign_rollno_form" name="Assign Roll Number" parent="menu_configuration" action="action_assign_roll_no_form" />
</odoo>
# See LICENSE file for full copyright and licensing details.
from odoo import models, fields
class MoveStandards(models.TransientModel):
"""Defining TransientModel to move standard."""
_name = 'move.standards'
_description = "Move Standards"
academic_year_id = fields.Many2one('academic.year', 'Academic Year',
required=True)
def move_start(self):
'''Code for moving student to next standard'''
academic_obj = self.env['academic.year']
school_stand_obj = self.env['school.standard']
standard_obj = self.env["standard.standard"]
student_obj = self.env['student.student']
done_rec = student_obj.search([('state', '=', 'done')])
for stud in done_rec:
year_id = academic_obj.next_year(stud.year.sequence)
academic_year = academic_obj.search([('id', '=', year_id)],
limit=1)
standard_seq = stud.standard_id.standard_id.sequence
next_class_id = standard_obj.next_standard(standard_seq)
# Assign the academic year
if next_class_id:
division = (stud.standard_id.division_id.id or False)
next_stand = school_stand_obj.search([
('standard_id', '=', next_class_id),
('division_id', '=', division),
('school_id', '=', stud.school_id.id),
('medium_id', '=', stud.medium_id.id)])
if next_stand:
std_vals = {'year': academic_year.id,
'standard_id': next_stand.id}
# Move student to next standard
stud.write(std_vals)
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Assign Roll Number Wizard Form View -->
<record id="view_move_standards_form" model="ir.ui.view">
<field name="name">move_standards.form</field>
<field name="model">move.standards</field>
<field name="arch" type="xml">
<form string="Move Classes">
<group>
<field name="academic_year_id" placeholder="Enter Academic Year" widget="selection"/>
</group>
<footer>
<button class="btn btn-sm btn-default fa fa-ban" special="cancel" string="Close"/>
<button class="btn btn-sm btn-default fa fa-plus" name="move_start" string="Move" type="object"/>
</footer>
</form>
</field>
</record>
<!-- Action Of Form & Tree Views Of Move Classes -->
<record id="action_move_standards_form" model="ir.actions.act_window">
<field name="name">Move Classes</field>
<field name="res_model">move.standards</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_move_standards_form" />
<field name="target">new</field>
</record>
<!-- MenuItem For Configurations->Move Classes -->
<menuitem id="menu_move_standards_form" name="Move Classes" parent="menu_configuration" action="action_move_standards_form" />
</odoo>
# See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class TerminateReason(models.TransientModel):
"""Defining TransientModel to terminate reason."""
_name = "terminate.reason"
_description = "Terminate Reason"
reason = fields.Text('Reason')
def save_terminate(self):
'''Method to terminate student and change state to terminate.'''
self.env['student.student'].browse(
self._context.get('active_id')).write({
'state': 'terminate',
'terminate_reason': self.reason,
'active': False})
student_rec = self.env['student.student'].browse(
self._context.get('active_id'))
student_rec.standard_id._compute_total_student()
user = self.env['res.users'].search([
('id', '=', student_rec.user_id.id)])
student_reminder = self.env['student.reminder'].search([
('stu_id', '=', student_rec.id)])
for rec in student_reminder:
rec.active = False
if user:
user.active = False
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Form View of terminate student wizard -->
<record id="school_terminate_reason" model="ir.ui.view">
<field name="name">Terminate Reason</field>
<field name="model">terminate.reason</field>
<field name="arch" type="xml">
<form string="Terminate Wizard">
<sheet>
<group>
<field name="reason" required="1" nolabel="1" placeholder="Reason"/>
</group>
<footer>
<button name="save_terminate" string="Terminate" type="object"/>
<button special="cancel" string="Cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
<!-- Action of Terminate Student Wizard -->
<record id="action_terminate_wizard" model="ir.actions.act_window">
<field name="name">Termination Reason</field>
<field name="res_model">terminate.reason</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</odoo>
# See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class MailTemplate(models.Model):
_inherit = "mail.template"
def generate_email(self, res_ids, fields=None):
'''Method to generate email.'''
ret = super(MailTemplate, self).generate_email(res_ids, fields=fields)
if (self._context.get('body_html', False) or
self._context.get('subject', False) or
self._context.get('email_to', False)):
ret['body_html'] = self._context['body_text']
ret['subject'] = self._context['subject']
ret['email_to'] = self._context['email_to']
return ret
#
#
class SendMail(models.TransientModel):
"""Defining TransientModel to send mail."""
_name = "send.email"
_description = "Send Mail"
note = fields.Text('Text')
def send_email(self):
'''Method to send email.'''
body = ''
email_template_obj = self.env['mail.template']
# search the model student.student
template_id = email_template_obj.search([
('model', '=', 'student.student')],
limit=1)
if template_id:
for i in self:
body += '\n' + i.note
email_template_obj.send_mail(template_id.id,
self._context.get('active_id'),
force_send=True)
return {'type': 'ir.actions.act_window_close'}
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Form View Of Send Mail -->
<record id="wiz_send_email_form_view" model="ir.ui.view">
<field name="name">send.email.form</field>
<field name="model">send.email</field>
<field name="arch" type="xml">
<form string="Send Email">
<field name='note' nolabel="0" height="350" width="350" placeholder="Notes"/>
<br/>
<footer>
<button name="send_email" string="Send Email" class="btn btn-sm btn-default fa fa-envelope" type="object"/>
<button special="cancel" string="Cancel"/>
</footer>
</form>
</field>
</record>
<!-- Action Of Form View Of Send Mail -->
<record id="act_send_email" model="ir.actions.act_window">
<field name="name">Send Email</field>
<field name="res_model">send.email</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="binding_model_id" ref="model_student_student"/>
<field name="binding_view_types">form</field>
<field name="groups_id" eval="[(4, ref('school.group_school_administration')),
(4, ref('school.group_school_teacher'))]"/>
</record>
</odoo>
...@@ -11,7 +11,7 @@ FARMING MANAGEMENT ...@@ -11,7 +11,7 @@ FARMING MANAGEMENT
'category': 'IDG MANAGEMENT', 'category': 'IDG MANAGEMENT',
'website': 'https://opensipkd.com', 'website': 'https://opensipkd.com',
'images': [], 'images': [],
'depends': ['base_geoengine', 'id_gov', 'contacts', 'mrp'], 'depends': ['base_geoengine', 'id_gov', 'contacts', 'project', 'fleet', ],
'data': [ 'data': [
'security/account_security.xml', 'security/account_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
......
from odoo import api, fields, models from odoo import api, fields, models
import logging
log = logging.getLogger(__name__)
class ResPartner(models.Model): class ResPartner(models.Model):
_description = 'Location' _description = 'Location'
_inherit = 'res.partner' _inherit = 'res.partner'
is_location = fields.Boolean(index=True)
geom = fields.GeoPolygon(index=True) geom = fields.GeoPolygon(index=True)
def search(self, args, offset=0, limit=None, order=None, count=False):
# this could have a check for this add domain based on a context value
partner_id = self.env.user.partner_id
args.append(('parent_id', '=', partner_id.id))
return super(ResPartner, self). \
search(args, offset, limit, order, count)
@api.model_create_multi
def create(self, values):
for val in values:
is_location = val.get('is_location')
company_id = val.get('company_id')
parent_id = val.get('parent_id')
if is_location:
if not company_id and not parent_id:
partner_id = self.env.user.partner_id
val['parent_id'] = partner_id.id
return super(ResPartner, self).create(values)
"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_tandur_user_partner","res_partner group_tandur_user","model_res_partner","group_tandur_user",0,1,1,1 "access_tandur_user_partner","res_partner group_tandur_user","model_res_partner","group_tandur_user",0,1,1,1
"access_tandur_price_hist","access.tandur.price.hist","model_tandur_price_hist","base.group_user",1,0,0,0 "access_tandur_price_hist","access.tandur.price.hist","model_tandur_price_hist","base.group_user",1,0,0,0
"access_tandur_ir_model","access.tandur.ir.model","base.model_ir_model","base.group_user",1,0,0,0
"access_tandur_ir_ui_view","access.tandur.ir.ui.view","base.model_ir_ui_view","base.group_user",1,0,0,0
"access_tandur_price_hist_admin","access.tandur.price.hist.admin","model_tandur_price_hist","group_tandur_admin",1,1,1,1 "access_tandur_price_hist_admin","access.tandur.price.hist.admin","model_tandur_price_hist","group_tandur_admin",1,1,1,1
"access_tandur_geom_test","access.tandur.geom.test.admin","model_geom_test","group_tandur_admin",1,1,1,1 "access_tandur_geom_test","access.tandur.geom.test.admin","model_geom_test","group_tandur_admin",1,1,1,1
...@@ -4,17 +4,17 @@ ...@@ -4,17 +4,17 @@
<record id="partner_form_tandur" model="ir.ui.view"> <record id="partner_form_tandur" model="ir.ui.view">
<field name="name">partner.form.tandur.inherit</field> <field name="name">partner.form.tandur.inherit</field>
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field name="priority">80</field> <field name="priority">1</field>
<field name="inherit_id" ref="id_gov.partner_form_id"/> <field name="inherit_id" ref="id_gov.partner_form_id"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='child_ids']//form//field[@name='parent_id']" position="after"> <xpath expr="//notebook//page[@name='contact_addresses']" position="before">
<page string="Map">
<group> <group>
<notebook> <field name="is_location" string="Is Location"/>
<page string="Geometry"> </group>
<field name="geom" widget="geo_edit_map"/> <field name="geom" widget="geo_edit_map"/>
</page> </page>
</notebook>
</group>
</xpath> </xpath>
</field> </field>
</record> </record>
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
<field name="geom"/> <field name="geom"/>
</geoengine> </geoengine>
</field> </field>
<field eval="16" name="priority"/> <!-- <field eval="16" name="priority"/>-->
</record> </record>
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
<record id="tandur_location_action" model="ir.actions.act_window"> <record id="tandur_location_action" model="ir.actions.act_window">
<field name="name">Location</field> <field name="name">Location</field>
<field name="res_model">res.partner</field> <field name="res_model">res.partner</field>
<field name="context">{'default_is_location':True}</field>
<field name="domain">[('is_location','=',True)]</field>
<field name="view_mode">kanban,tree,form,geoengine</field> <field name="view_mode">kanban,tree,form,geoengine</field>
<field name="help" type="html"> <field name="help" type="html">
......
=========
Timetable
=========
This module was written to extend the functionality of timetable management to support school management and allows you to manage timetable through this functionality.
Installation
============
To install this module, you need to:
install school module
Configuration
=============
To configure this module, you need to:
have a school Management functionality.
Usage
=====
To use this module, you need to:
go to apps, then install module to apply this functionality.
Try me on Runbot
Known issues / Roadmap
Bug Tracker
===========
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed feedback here.
=======
Credits
=======
Contributors
============
Serpent Consulting Services PVT. LTD. <http://serpentcs.com>
Maintainer
==========
Serpent Consulting Services PVT. LTD.
This module is maintained by the SerpentCS.
To contribute to this module, please visit http://serpentcs.com.
# See LICENSE file for full copyright and licensing details.
# ----------------------------------------------------------
# A Module for School Timetable Management System
# ----------------------------------------------------------
from . import models
from . import report
# See LICENSE file for full copyright and licensing details.
{
'name': 'Timetable Management',
'version': '14.0.1.0.0',
'author': '''Serpent Consulting Services Pvt. Ltd.''',
'website': 'http://www.serpentcs.com',
'license': "AGPL-3",
'category': 'School Management',
'complexity': 'easy',
'summary': 'A Module For Timetable Management In School',
'images': ['static/description/SchoolTimetable.png'],
'depends': ['school'],
'data': ['security/timetable_security.xml',
'security/ir.model.access.csv',
'report/report_view.xml',
'report/timetable.xml',
'views/timetable_view.xml',],
'demo': ['demo/timetable_demo.xml'],
'installable': True,
'application': True
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!