Files
Odoo-Tutorial/CatEdu/openeducat_admission/models/admission.py
T
2025-05-05 09:03:48 +07:00

509 lines
21 KiB
Python

##############################################################################
#
# OpenEduCat Inc
# Copyright (C) 2009-TODAY OpenEduCat Inc(<https://www.openeducat.org>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
class OpAdmission(models.Model):
_name = "op.admission"
_inherit = ['mail.thread', 'mail.activity.mixin',
'mail.tracking.duration.mixin']
_rec_name = "application_number"
_description = "Admission"
_order = 'id DESC'
name = fields.Char(
'Name', required=True, translate=True)
first_name = fields.Char(
'First Name', required=True, translate=True)
middle_name = fields.Char(
'Middle Name', translate=True)
last_name = fields.Char(
'Last Name', required=True, translate=True)
title = fields.Many2one(
'res.partner.title', 'Title')
application_number = fields.Char(
'Application Number', size=16, copy=False,
readonly=True, store=True)
admission_date = fields.Date(
'Admission Date', copy=False)
application_date = fields.Datetime(
'Application Date', required=True, copy=False,
default=lambda self: fields.Datetime.now())
birth_date = fields.Date(
'Birth Date', required=True)
course_id = fields.Many2one(
'op.course', 'Course', required=True)
batch_id = fields.Many2one(
'op.batch', 'Batch', required=False)
street = fields.Char(
'Street', size=256)
street2 = fields.Char(
'Street2', size=256)
phone = fields.Char(
'Phone', size=16)
mobile = fields.Char(
'Mobile', size=16)
email = fields.Char(
'Email', size=256, required=True)
city = fields.Char('City', size=64)
zip = fields.Char('Zip', size=8)
state_id = fields.Many2one(
'res.country.state', 'States', domain="[('country_id', '=', country_id)]")
country_id = fields.Many2one(
'res.country', 'Country')
fees = fields.Float('Fees')
image = fields.Image('image')
state = fields.Selection(
[('draft', 'Draft'), ('submit', 'Submitted'),
('confirm', 'Confirmed'), ('admission', 'Admission Confirm'),
('reject', 'Rejected'), ('pending', 'Pending'),
('cancel', 'Cancelled'), ('done', 'Done')],
'State', default='draft', tracking=True)
due_date = fields.Date('Due Date')
prev_institute_id = fields.Char('Previous Institute')
prev_course_id = fields.Char('Previous Course')
prev_result = fields.Char(
'Previous Result', size=256)
family_business = fields.Char(
'Family Business', size=256)
family_income = fields.Float(
'Family Income')
gender = fields.Selection(
[('m', 'Male'), ('f', 'Female')],
string='Gender',
required=True)
student_id = fields.Many2one(
'op.student', 'Student')
nbr = fields.Integer('No of Admission', readonly=True)
register_id = fields.Many2one(
'op.admission.register', 'Admission Register', required=True)
partner_id = fields.Many2one('res.partner', 'Partner')
is_student = fields.Boolean('Is Already Student')
fees_term_id = fields.Many2one('op.fees.terms', 'Fees Term')
active = fields.Boolean(default=True)
discount = fields.Float(string='Discount (%)',
digits='Discount', default=0.0)
fees_start_date = fields.Date('Fees Start Date')
company_id = fields.Many2one(
'res.company', string='Company',
default=lambda self: self.env.user.company_id)
program_id = fields.Many2one('op.program', string="Program", tracking=True)
course_ids = fields.Many2many('op.course', string='Courses',
compute='_compute_course_ids')
_sql_constraints = [
('unique_application_number',
'unique(application_number)',
'Application Number must be unique per Application!'),
]
@api.depends('register_id')
def _compute_course_ids(self):
for data in self:
if data.register_id:
if data.register_id.admission_base == 'program':
course_list = []
for rec in data.register_id.admission_fees_line_ids:
course_list.append(rec.course_id.id) if rec.course_id.id not in course_list else None # noqa
data.course_ids = [(6, 0, course_list)]
else:
data.course_id = data.register_id.course_id.id
data.course_ids = [(6, 0, [data.register_id.course_id.id])]
else:
data.course_ids = [(6, 0, [])]
@api.onchange('first_name', 'middle_name', 'last_name')
def _onchange_name(self):
if not self.middle_name:
self.name = str(self.first_name) + " " + str(
self.last_name
)
else:
self.name = str(self.first_name) + " " + str(
self.middle_name) + " " + str(self.last_name)
@api.onchange('student_id', 'is_student')
def onchange_student(self):
if self.is_student and self.student_id:
sd = self.student_id
self.title = sd.title and sd.title.id or False
self.first_name = sd.first_name
self.middle_name = sd.middle_name
self.last_name = sd.last_name
self.birth_date = sd.birth_date
self.gender = sd.gender
self.image = sd.image_1920 or False
self.street = sd.street or False
self.street2 = sd.street2 or False
self.phone = sd.phone or False
self.mobile = sd.mobile or False
self.email = sd.email or False
self.zip = sd.zip or False
self.city = sd.city or False
self.country_id = sd.country_id and sd.country_id.id or False
self.state_id = sd.state_id and sd.state_id.id or False
self.partner_id = sd.partner_id and sd.partner_id.id or False
else:
self.birth_date = ''
self.gender = ''
self.image = False
self.street = ''
self.street2 = ''
self.phone = ''
self.mobile = ''
self.zip = ''
self.city = ''
self.country_id = False
self.state_id = False
self.partner_id = False
@api.onchange('register_id')
def onchange_register(self):
if self.register_id:
if self.register_id.admission_base == 'course':
self.program_id = self.course_id.program_id.id
self.fees = self.register_id.product_id.lst_price
self.company_id = self.register_id.company_id.id
else:
self.program_id = self.register_id.program_id.id
@api.onchange('course_id')
def onchange_course(self):
self.batch_id = False
term_id = False
if self.course_id:
if self.register_id.admission_base == 'program':
for rec in self.register_id.admission_fees_line_ids:
if rec.course_id.id == self.course_id.id:
self.fees = rec.course_fees_product_id.lst_price
self.program_id = self.course_id.program_id.id
if self.course_id.fees_term_id:
term_id = self.course_id.fees_term_id.id
self.fees_term_id = term_id
@api.constrains('register_id', 'application_date')
def _check_admission_register(self):
for rec in self:
start_date = fields.Date.from_string(rec.register_id.start_date)
end_date = fields.Date.from_string(rec.register_id.end_date)
application_date = fields.Date.from_string(rec.application_date)
if application_date < start_date or application_date > end_date:
raise ValidationError(_(
"Application Date should be between Start Date & End Date of Admission Register.")) # noqa
@api.constrains('birth_date')
def _check_birthdate(self):
for record in self:
if record.birth_date and record.birth_date > fields.Date.today():
raise ValidationError(_(
"Birth Date can't be greater than current date!"))
elif record and record.birth_date:
today_date = fields.Date.today()
day = (today_date - record.birth_date).days
years = day // 365
if years < self.register_id.minimum_age_criteria:
raise ValidationError(_(
"Not Eligible for Admission minimum "
"required age is :"
" %s " % self.register_id.minimum_age_criteria))
@api.constrains('name')
def create_sequence(self):
if not self.application_number:
self.application_number = self.env['ir.sequence'].next_by_code(
'op.admission') or '/'
def submit_form(self):
self.state = 'submit'
def admission_confirm(self):
self.state = 'admission'
def confirm_in_progress(self):
for record in self:
record.state = 'confirm'
def get_student_vals(self):
enable_create_student_user = self.env['ir.config_parameter'].get_param(
'openeducat_admission.enable_create_student_user')
for student in self:
student_user = False
if enable_create_student_user:
student_user = self.env['res.users'].create({
'name': student.name,
'login': student.email if student.email else student.application_number, # noqa
'image_1920': self.image or False,
'is_student': True,
'company_id': self.company_id.id,
'groups_id': [
(6, 0,
[self.env.ref('base.group_portal').id])]
})
details = {
'name': student.name,
'phone': student.phone,
'mobile': student.mobile,
'email': student.email,
'street': student.street,
'street2': student.street2,
'city': student.city,
'country_id':
student.country_id and student.country_id.id or False,
'state_id': student.state_id and student.state_id.id or False,
'image_1920': student.image,
'zip': student.zip,
}
if enable_create_student_user:
student_user.partner_id.write(details)
details.update({
'title': student.title and student.title.id or False,
'first_name': student.first_name,
'middle_name': student.middle_name,
'last_name': student.last_name,
'birth_date': student.birth_date,
'gender': student.gender if student.gender else False,
'image_1920': student.image or False,
'course_detail_ids': [[0, False, {
'course_id':
student.course_id and student.course_id.id or False,
'batch_id':
student.batch_id and student.batch_id.id or False,
'academic_years_id':
student.register_id.academic_years_id.id or False,
'academic_term_id':
student.register_id.academic_term_id.id or False,
'fees_term_id': student.fees_term_id.id,
'fees_start_date': student.fees_start_date,
'product_id': student.register_id.product_id.id,
}]],
'user_id': student_user.id if student_user else False,
'company_id': self.company_id.id
})
return details
def enroll_student(self):
for record in self:
if record.register_id.max_count:
total_admission = self.env['op.admission'].search_count(
[('register_id', '=', record.register_id.id),
('state', '=', 'done')])
if not total_admission < record.register_id.max_count:
msg = 'Max Admission In Admission Register :- (%s)' % (
record.register_id.max_count)
raise ValidationError(_(msg))
if not record.student_id:
vals = record.get_student_vals()
if vals:
record.student_id = student_id = self.env[
'op.student'].create(vals).id
record.partner_id = record.student_id.partner_id.id \
if record else False
else:
student_id = record.student_id.id
record.student_id.write({
'course_detail_ids': [[0, False, {
'course_id':
record.course_id and record.course_id.id or False,
'batch_id':
record.batch_id and record.batch_id.id or False,
'fees_term_id': record.fees_term_id.id,
'fees_start_date': record.fees_start_date,
'product_id': record.register_id.product_id.id,
}]],
})
if record.fees_term_id.fees_terms in ['fixed_days', 'fixed_date']:
val = []
product_id = record.register_id.product_id.id
for line in record.fees_term_id.line_ids:
no_days = line.due_days
per_amount = line.value
amount = (per_amount * record.fees) / 100
dict_val = {
'fees_line_id': line.id,
'amount': amount,
'fees_factor': per_amount,
'product_id': product_id,
'discount': record.discount or record.fees_term_id.discount,
'state': 'draft',
'course_id': record.course_id and record.course_id.id or False,
'batch_id': record.batch_id and record.batch_id.id or False,
}
if line.due_date:
date = line.due_date
dict_val.update({
'date': date
})
elif self.fees_start_date:
date = self.fees_start_date + relativedelta(
days=no_days)
dict_val.update({
'date': date,
})
else:
date_now = (datetime.today() + relativedelta(
days=no_days)).date()
dict_val.update({
'date': date_now,
})
val.append([0, False, dict_val])
record.student_id.write({
'fees_detail_ids': val
})
record.write({
'nbr': 1,
'state': 'done',
'admission_date': fields.Date.today(),
'student_id': student_id,
'is_student': True,
})
reg_id = self.env['op.subject.registration'].create({
'student_id': student_id,
'batch_id': record.batch_id.id,
'course_id': record.course_id.id,
'min_unit_load': record.course_id.min_unit_load or 0.0,
'max_unit_load': record.course_id.max_unit_load or 0.0,
'state': 'draft',
})
reg_id.get_subjects()
def confirm_rejected(self):
self.state = 'reject'
def confirm_pending(self):
self.state = 'pending'
def confirm_to_draft(self):
self.state = 'draft'
def confirm_cancel(self):
self.state = 'cancel'
if self.is_student and self.student_id.fees_detail_ids:
self.student_id.fees_detail_ids.state = 'cancel'
def payment_process(self):
self.state = 'fees_paid'
def open_student(self):
form_view = self.env.ref('openeducat_core.view_op_student_form')
tree_view = self.env.ref('openeducat_core.view_op_student_tree')
value = {
'domain': str([('id', '=', self.student_id.id)]),
'view_type': 'form',
'view_mode': 'list, form',
'res_model': 'op.student',
'view_id': False,
'views': [(form_view and form_view.id or False, 'form'),
(tree_view and tree_view.id or False, 'list')],
'type': 'ir.actions.act_window',
'res_id': self.student_id.id,
'target': 'current',
'nodestroy': True
}
self.state = 'done'
return value
def create_invoice(self):
""" Create invoice for fee payment process of student """
partner_id = self.env['res.partner'].create({'name': self.name})
account_id = False
product = self.register_id.product_id
if product.id:
account_id = product.property_account_income_id.id
if not account_id:
account_id = product.categ_id.property_account_income_categ_id.id
if not account_id:
raise UserError(
_('There is no income account defined for this product: "%s". \
You may have to install a chart of account from Accounting \
app, settings menu.') % (product.name,))
if self.fees <= 0.00:
raise UserError(
_('The value of the deposit amount must be positive.'))
amount = self.fees
name = product.name
invoice = self.env['account.invoice'].create({
'name': self.name,
'origin': self.application_number,
'move_type': 'out_invoice',
'reference': False,
'account_id': partner_id.property_account_receivable_id.id,
'partner_id': partner_id.id,
'invoice_line_ids': [(0, 0, {
'name': name,
'origin': self.application_number,
'account_id': account_id,
'price_unit': amount,
'quantity': 1.0,
'discount': 0.0,
'uom_id': self.register_id.product_id.uom_id.id,
'product_id': product.id,
})],
})
invoice.compute_taxes()
form_view = self.env.ref('account.invoice_form')
tree_view = self.env.ref('account.invoice_tree')
value = {
'domain': str([('id', '=', invoice.id)]),
'view_type': 'form',
'view_mode': 'form',
'res_model': 'account.invoice',
'view_id': False,
'views': [(form_view and form_view.id or False, 'form'),
(tree_view and tree_view.id or False, 'list')],
'type': 'ir.actions.act_window',
'res_id': invoice.id,
'target': 'current',
'nodestroy': True
}
self.partner_id = partner_id
self.state = 'payment_process'
return value
@api.model
def get_import_templates(self):
return [{
'label': _('Import Template for Admission'),
'template': '/openeducat_admission/static/xls/op_admission.xls'
}]
class OpStudentCourseInherit(models.Model):
_inherit = "op.student.course"
product_id = fields.Many2one(
'product.product', 'Course Fees',
domain=[('type', '=', 'service')], tracking=True)
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
enable_create_student_user = fields.Boolean(
config_parameter='openeducat_admission.enable_create_student_user',
string='Create Student User')