1106 lines
41 KiB
Python
1106 lines
41 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from odoo import models, fields, api, _
|
|
from odoo.exceptions import ValidationError
|
|
from random import randint
|
|
from datetime import date
|
|
import logging
|
|
import os
|
|
import re
|
|
SAUDI_MOBILE_PATTERN = "(^(05|5)(5|0|3|6|4|9|1|8|7)([0-9]{7})$)"
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class BenefitCategory(models.Model):
|
|
_name = 'benefit.category'
|
|
_description = "Benefits - category"
|
|
|
|
name = fields.Char(string="Category Name")
|
|
description = fields.Char(string="Description")
|
|
gender = fields.Selection(selection=[('male', _('Male')), ('female', _('Female')) ,('both', _('Both'))], string="Gender")
|
|
age_from = fields.Integer(string="From")
|
|
age_to = fields.Integer(string="To")
|
|
benefit_ids = fields.One2many('grant.benefit', 'benefit_category_id', string="Category Benefits")
|
|
benefits_total = fields.Integer(string="Benefit Total", compute="get_benefits_total")
|
|
mini_income_amount = fields.Float(string="Min Income Amount")
|
|
max_income_amount = fields.Float(string="Max Income Amount")
|
|
expenses_ids = fields.One2many('expenses.line', 'category_id')
|
|
is_benefit = fields.Boolean(string="Is Benefit",default=True)
|
|
color = fields.Integer(string="Color Index", default=0)
|
|
decoration_color = fields.Selection([
|
|
('danger', 'Red'),
|
|
('success', 'Green'),
|
|
('warning', 'Orange'),
|
|
('info', 'Blue'),
|
|
('primary', 'Primary'),
|
|
('muted', 'Muted'),
|
|
])
|
|
|
|
|
|
def get_benefits_total(self):
|
|
for rec in self:
|
|
rec.benefits_total = len(rec.benefit_ids)
|
|
|
|
def open_benefits(self):
|
|
return {
|
|
'name': _("Benefits"),
|
|
'view_type': 'form',
|
|
'view_mode': 'tree,form',
|
|
'views': [(self.env.ref(
|
|
'odex_benefit.grant_benefit_tree').id, 'tree'),
|
|
(self.env.ref('odex_benefit.grant_benefit_form').id, 'form')],
|
|
'res_model': 'grant.benefit',
|
|
'type': 'ir.actions.act_window',
|
|
'domain': [('id', 'in', self.benefit_ids.ids)],
|
|
'target': 'current',
|
|
}
|
|
|
|
|
|
class GrantFamily(models.Model):
|
|
_name = 'benefit.family'
|
|
_description = "Benefits - family"
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
responsible_benefit_id = fields.Many2one(
|
|
'grant.benefit',
|
|
domain="[('is_responsible','=',True),('family_id','=',id)]")
|
|
housing_id = fields.Many2one(
|
|
'benefit.housing')
|
|
loan_ids = fields.Many2many('benefit.loans', 'family_id')
|
|
total_expenses = fields.Float(
|
|
compute='get_total_needs_percent',
|
|
string='Total Expenses of Family',
|
|
required=False)
|
|
total_income = fields.Float(
|
|
compute='get_total_needs_percent',
|
|
string='Total Income of Family',
|
|
required=False)
|
|
benefit_needs_percent = fields.Float(
|
|
compute='get_total_needs_percent',
|
|
string='',
|
|
store=True,
|
|
required=False)
|
|
is_producer = fields.Boolean(string='Producer')
|
|
description = fields.Char(string="Description")
|
|
benefits_total = fields.Integer(string="Benefit Total", compute="get_benefits_total", store=True)
|
|
benefit_ids = fields.One2many('grant.benefit', 'family_id', string="Benefits")
|
|
|
|
@api.depends("benefit_ids")
|
|
def get_benefits_total(self):
|
|
for rec in self:
|
|
rec.benefits_total = len(rec.benefit_ids)
|
|
|
|
def get_total_needs_percent(self):
|
|
for rec in self:
|
|
if rec.benefit_ids:
|
|
percent = 0.0
|
|
for amount in rec.benefit_ids:
|
|
rec.total_income += amount.total_income
|
|
rec.total_expenses += amount.total_expenses
|
|
percent += amount.benefit_needs_percent
|
|
rec.benefit_needs_percent = percent / len(rec.benefit_ids)
|
|
else:
|
|
rec.benefit_needs_percent = 0.0
|
|
rec.total_income = 0.0
|
|
rec.total_expenses = 0.0
|
|
|
|
|
|
def open_benefits(self):
|
|
return {
|
|
'name': "Benefits",
|
|
'view_type': 'form',
|
|
'view_mode': 'tree,form',
|
|
'views': [(self.env.ref(
|
|
'odex_benefit.grant_benefit_tree').id, 'tree'),
|
|
(self.env.ref('odex_benefit.grant_benefit_form').id, 'form')],
|
|
'res_model': 'grant.benefit',
|
|
'type': 'ir.actions.act_window',
|
|
'domain': "[('family_id','=',%s)]" % (self.id),
|
|
'target': 'current',
|
|
}
|
|
|
|
|
|
class SportLine(models.Model):
|
|
_name = 'sport.line'
|
|
_description = "Benefits - sport"
|
|
|
|
benefit_id = fields.Many2one(
|
|
'grant.benefit')
|
|
sport_type = fields.Many2one(
|
|
'sport.type')
|
|
sport_attendance = fields.Boolean(
|
|
string='',
|
|
required=False)
|
|
Subtype = fields.Selection(
|
|
string='Subtype',
|
|
selection=[('daily', 'daily'),
|
|
('monthly', 'Monthly'),
|
|
('yearly', 'yearly'),
|
|
], )
|
|
sport_time = fields.Selection(
|
|
string='Sport Time',
|
|
selection=[('morning', 'Morning'),
|
|
('day', 'day'),
|
|
('evening', 'evening'),
|
|
],
|
|
required=False, )
|
|
sport_club = fields.Char(
|
|
string='',
|
|
required=False)
|
|
sport_amount = fields.Float(
|
|
string='',
|
|
required=False)
|
|
sport_clothing = fields.Char(
|
|
string='',
|
|
required=False)
|
|
sport_equipment = fields.Char(
|
|
string='',
|
|
required=False)
|
|
|
|
|
|
class SportType(models.Model):
|
|
_name = 'sport.type'
|
|
_description = "Benefits - sport Type"
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
description = fields.Char(
|
|
string='Description',
|
|
required=False)
|
|
|
|
|
|
class CraftSkills(models.Model):
|
|
_name = 'craft.skills'
|
|
_description = "Benefits - sport"
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
benefit_id = fields.Many2one(
|
|
'grant.benefit')
|
|
is_invested = fields.Boolean(
|
|
string='',
|
|
required=False)
|
|
skill_rating = fields.Float(
|
|
string='',
|
|
required=False)
|
|
is_development = fields.Boolean(
|
|
string='',
|
|
required=False)
|
|
is_capital = fields.Boolean(
|
|
string='',
|
|
required=False)
|
|
is_work_place = fields.Boolean(
|
|
string='',
|
|
required=False)
|
|
work_history = fields.Char(
|
|
string='',
|
|
required=False)
|
|
achievements = fields.Char(
|
|
string='',
|
|
required=False)
|
|
certificates = fields.Binary(string="")
|
|
# Awards and certificates # TODO#
|
|
|
|
|
|
class inclination(models.Model):
|
|
_name = 'training.inclinations'
|
|
_description = "Benefits - inclination"
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
benefit_id = fields.Many2one(
|
|
'grant.benefit')
|
|
training_type_id = fields.Many2one('training.type',
|
|
string='',
|
|
required=False)
|
|
is_invested = fields.Boolean(
|
|
string='',
|
|
required=False)
|
|
training_rating = fields.Float(
|
|
string='',
|
|
required=False)
|
|
is_development = fields.Boolean(
|
|
string='',
|
|
required=False)
|
|
is_capital = fields.Boolean(
|
|
string='',
|
|
required=False)
|
|
training_history = fields.Char(
|
|
string='',
|
|
required=False)
|
|
book_history = fields.Char(
|
|
string='What books has he read?',
|
|
required=False)
|
|
courses = fields.Char(
|
|
string='What courses did he take?',
|
|
required=False)
|
|
steps = fields.Char(
|
|
string='',
|
|
required=False)
|
|
training_future = fields.Char(
|
|
string='',
|
|
required=False)
|
|
training_site = fields.Char(
|
|
string='',
|
|
required=False)
|
|
training_records = fields.Char(
|
|
string='',
|
|
required=False)
|
|
achievements = fields.Char()
|
|
certificates = fields.Binary(string="")
|
|
# Awards and certificates
|
|
|
|
|
|
class BenefitBehaviors(models.Model):
|
|
_name = 'benefit.behaviors'
|
|
_description = "Benefits - behaviors"
|
|
|
|
name = fields.Char(
|
|
related='behavior_id.name')
|
|
benefit_id = fields.Many2one(
|
|
'grant.benefit')
|
|
behavior_id = fields.Many2one(
|
|
'benefit.behaviors.type')
|
|
behavior_date = fields.Date(
|
|
string='',
|
|
required=False)
|
|
need_help = fields.Boolean(
|
|
string='',
|
|
required=False)
|
|
|
|
|
|
class BenefitBehaviorsType(models.Model):
|
|
_name = 'benefit.behaviors.type'
|
|
_description = "Benefits - behaviors type"
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
type = fields.Selection(
|
|
string='',
|
|
selection=[('negative', 'Negative'),
|
|
('positive', 'Positive'), ],
|
|
required=False, )
|
|
|
|
|
|
class Salary(models.Model):
|
|
_name = 'salary.line'
|
|
_description = "Benefits - Salary line"
|
|
|
|
benefit_id = fields.Many2one(
|
|
'grant.benefit')
|
|
mother_benefit_id = fields.Many2one('grant.benefit', string="Mother Benefit", ondelete='cascade')
|
|
currency_id = fields.Many2one('res.currency', related='benefit_id.currency_id')
|
|
salary_type = fields.Char()
|
|
income_type = fields.Many2one('attachments.settings',string='Income Type',domain="[('attach_type','=','income_attach')]")
|
|
salary_amount = fields.Float(
|
|
string='Income Amount',
|
|
required=False)
|
|
salary_attach = fields.Many2many('ir.attachment',string="Attachment")
|
|
attach_start_date = fields.Date(string='Attach Start Date')
|
|
attach_end_date = fields.Date(string='Attach End Date')
|
|
is_required = fields.Boolean(string='Is Required?')
|
|
is_mother_salary = fields.Boolean(string="Is Mother Salary", default=False)
|
|
approved = fields.Boolean(string="Is Approved", default=False)
|
|
is_default = fields.Boolean(string='Is Default?')
|
|
state = fields.Selection(string='Status',selection=[('waiting', 'Waiting'),('accepted', 'Accepted'),('refused', 'Refused')],default="waiting")
|
|
note = fields.Char(string="Note")
|
|
# total_salary = fields.Float(string="Total Salary", compute='_compute_total_salary',store=True)
|
|
|
|
# @api.depends('salary_amount','state')
|
|
# def _compute_total_salary(self):
|
|
# total = 0
|
|
# for record in self:
|
|
# # Apply your custom condition here
|
|
# records = self.env['salary.line'].search([('state', '=', 'accepted')])
|
|
# for rec in records:
|
|
# total += rec.salary_amount
|
|
# record.total_salary = total
|
|
|
|
@api.model
|
|
def create(self, vals):
|
|
if 'state' not in vals or vals.get('state') not in ['accepted', 'refused']:
|
|
vals['state'] = 'waiting'
|
|
return super(Salary, self).create(vals)
|
|
|
|
def write(self, vals):
|
|
if 'state' not in vals:
|
|
for rec in self:
|
|
if rec.state not in ['accepted', 'refused']:
|
|
vals['state'] = 'waiting'
|
|
break
|
|
return super(Salary, self).write(vals)
|
|
|
|
def action_accept(self):
|
|
self.state = 'accepted'
|
|
|
|
def action_refuse(self):
|
|
self.state = 'refused'
|
|
|
|
def get_salary_attachment_name(self):
|
|
"""Return salary attachment name without extension."""
|
|
if self.salary_attach:
|
|
return os.path.splitext(self.salary_attach.name)[0]
|
|
return ''
|
|
|
|
def get_notification_emails(self):
|
|
"""Return a list of valid emails to notify, removing False values."""
|
|
emails = self.benefit_id.researcher_id.employee_id.mapped('work_email') or []
|
|
|
|
emails.extend([
|
|
self.benefit_id.branch_custom_id.branch.manager_id.work_email,
|
|
self.benefit_id.branch_custom_id.branch.operation_manager_id.work_email
|
|
])
|
|
|
|
# Remove False or None values
|
|
emails = list(filter(None, emails)) # Filters out None and False values
|
|
|
|
return ','.join(emails) if emails else 'admin@example.com'
|
|
|
|
def action_send_attachment_expiry_email(self):
|
|
"""Send email notifications for attachments expiring today and log the body in the chatter."""
|
|
today = date.today()
|
|
salary_lines = self.search([('attach_end_date', '=', today)])
|
|
|
|
mail_template = self.env.ref('odex_benefit.email_salary_attachment_expiry')
|
|
if not mail_template:
|
|
raise ValidationError("Salary Attachment Expiry Mail template not found!")
|
|
|
|
for salary_line in salary_lines:
|
|
# Render the email body
|
|
email_body = mail_template._render_field('body_html', [salary_line.id], compute_lang=True)[salary_line.id]
|
|
|
|
# Send the email
|
|
mail_template.send_mail(salary_line.id, force_send=True)
|
|
|
|
# Post the email body in the chatter of benefit_id
|
|
if salary_line.benefit_id:
|
|
salary_line.benefit_id.message_post(
|
|
body=email_body,
|
|
subtype_xmlid="mail.mt_note" # Log as a note in the chatter
|
|
)
|
|
|
|
|
|
class ibanBanks(models.Model):
|
|
_inherit = 'res.bank'
|
|
_description = "Add iban details in bank screen"
|
|
|
|
iban = fields.Char("IBAN")
|
|
code = fields.Char(string='Code')
|
|
|
|
|
|
class benefitsExpensesLine(models.Model):
|
|
_name = 'benefit.expenses'
|
|
_description = "Benefits - expenses"
|
|
|
|
name = fields.Char()
|
|
benefit_id = fields.Many2one('grant.benefit')
|
|
expenses_type = fields.Selection(
|
|
string='',
|
|
selection=[('governmental', 'Governmental Expenses'),
|
|
('medical', 'Medical Expenses'),
|
|
('transportation', 'Transportation Expenses'),
|
|
('debts', 'Debts Expenses'),
|
|
('pandemics', 'Pandemics Expenses'),
|
|
('living', 'Living Expenses'),
|
|
('educational', 'Educational Expenses'),
|
|
('clothing', 'Clothing Expenses'),
|
|
],
|
|
required=False, )
|
|
expenses_fees_type = fields.Selection(
|
|
string='Fees Type',
|
|
selection=[('fixed', 'Fixed'),
|
|
('dynamic', 'dynamic')], required=False, )
|
|
medicine_type = fields.Selection(
|
|
string='Medicine Type',
|
|
selection=[('pills', 'pills'),
|
|
('drink', 'drink'),
|
|
('inhalation', 'inhalation')], required=False, )
|
|
diseases_type = fields.Selection(
|
|
string='Diseases Type',
|
|
selection=[('chronic', 'chronic'),
|
|
('psycho', 'psycho'),
|
|
('organic', 'organic')], required=False, )
|
|
trans_type = fields.Selection(
|
|
string='trans Type',
|
|
selection=[('general', 'General'),
|
|
('especially', 'Especially')], required=False, )
|
|
debt_reason = fields.Char(string='', required=False)
|
|
attach = fields.Binary(string="",attachment=True )
|
|
debt_type = fields.Selection(selection=[('necessary', 'Necessary'),
|
|
('need', 'Need'),
|
|
('improve', 'to improve'),
|
|
('case', 'case or not'),
|
|
('Installed', 'Installed or not'),
|
|
])
|
|
pandemics_explain = fields.Char(string='pandemics explain', required=False)
|
|
amount = fields.Float()
|
|
state = fields.Selection([('draft', 'Draft'),
|
|
('accreditation', 'Accreditation'),
|
|
], string='state', default="draft", tracking=True)
|
|
|
|
def action_accepted(self):
|
|
for i in self:
|
|
i.state = 'accreditation'
|
|
|
|
|
|
class cloth(models.Model):
|
|
_name = 'benefit.cloth'
|
|
|
|
name = fields.Char()
|
|
benefit_id = fields.Many2one('grant.benefit')
|
|
cloth_type = fields.Many2one('cloth.type')
|
|
cloth_size = fields.Many2one('cloth.size')
|
|
cloth_note = fields.Char()
|
|
|
|
|
|
class ClothType(models.Model):
|
|
_name = 'cloth.type'
|
|
|
|
name = fields.Char()
|
|
|
|
|
|
class ClothSize(models.Model):
|
|
_name = 'cloth.size'
|
|
|
|
name = fields.Char()
|
|
|
|
|
|
class ExpensesLine(models.Model):
|
|
_name = 'expenses.line'
|
|
|
|
category_id = fields.Many2one(
|
|
'benefit.category')
|
|
benefit_id = fields.Many2one('grant.benefit')
|
|
mother_benefit_id = fields.Many2one('grant.benefit',string="Mother Benefit",ondelete='cascade')
|
|
currency_id = fields.Many2one('res.currency', related='benefit_id.currency_id')
|
|
#expenses_type_custom = fields.Many2one('expenses.type')
|
|
expenses_type_custom = fields.Many2one('attachments.settings', string='Expenses Type Custom',
|
|
domain="[('attach_type','=','expense_attach')]")
|
|
expenses_type = fields.Selection(
|
|
string='',
|
|
selection=[('governmental', 'Governmental Expenses'),
|
|
('medical', 'Medical Expenses'),
|
|
('transportation', 'Transportation Expenses'),
|
|
('debts', 'Debts Expenses'),
|
|
('pandemics', 'Pandemics Expenses'),
|
|
('living', 'Living Expenses'),
|
|
('educational', 'Educational Expenses'),
|
|
('clothing', 'Clothing Expenses'),
|
|
],
|
|
required=False, )
|
|
amount = fields.Float()
|
|
note = fields.Char()
|
|
state = fields.Selection(string='Status', selection=[('waiting', 'Waiting'),('accepted', 'Accepted'), ('refused', 'Refused')],default="waiting")
|
|
expense_attachments = fields.Many2many('ir.attachment','expenses_line_attachment_rel','expense_line_id','attachment_id',string="Attachment")
|
|
deduct_from_family_income = fields.Boolean(string="Deduct from Family Income")
|
|
|
|
def action_accept(self):
|
|
# self.benefit_id.get_member_income()
|
|
self.state = 'accepted'
|
|
|
|
|
|
def action_refuse(self):
|
|
self.state = 'refused'
|
|
|
|
class EntityRefuseReason(models.Model):
|
|
_name = 'entity.refuse_reason'
|
|
|
|
name = fields.Text("Refuse Reason")
|
|
user_id = fields.Many2one('res.users', 'Assigned to', default=lambda self: self.env.user, index=True)
|
|
entity_id = fields.Many2one('grant.benefit', 'Benefit Id')
|
|
date = fields.Datetime(string='Refuse Date', default=fields.Datetime.now)
|
|
|
|
|
|
class specialization(models.Model):
|
|
_name = 'specialization.specialization'
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
description = fields.Char(
|
|
string='Description',
|
|
required=False)
|
|
is_scientific_specialty = fields.Boolean('Is Scientific Specialty?')
|
|
is_medical_specialty = fields.Boolean('Is Medical Specialty?')
|
|
|
|
|
|
class OtherAssociations(models.Model):
|
|
_name = 'other.associations'
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
city_id = fields.Many2one(
|
|
'res.country.city')
|
|
description = fields.Char(
|
|
string='Description',
|
|
required=False)
|
|
|
|
|
|
class Associations(models.Model):
|
|
_name = 'associations.line'
|
|
|
|
benefit_id = fields.Many2one(
|
|
'grant.benefit')
|
|
associations_ids = fields.Many2one(
|
|
'other.associations',
|
|
string='Other Associations',
|
|
required=False)
|
|
support_type = fields.Selection(
|
|
string='',
|
|
selection=[('material', 'Material'),
|
|
('cash', 'cash'),
|
|
('both', 'Both'),
|
|
],
|
|
required=False, )
|
|
support_amount = fields.Float(
|
|
string='',
|
|
required=False)
|
|
associations_description = fields.Text(
|
|
string="",
|
|
required=False)
|
|
|
|
|
|
class Hospital(models.Model):
|
|
_name = 'hospital.hospital'
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
Location = fields.Char(
|
|
string='',
|
|
required=False)
|
|
|
|
|
|
class InsuranceCompany(models.Model):
|
|
_name = 'insurance.company'
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
description = fields.Char(
|
|
string='Description',
|
|
required=False)
|
|
|
|
|
|
class InsuranceType(models.Model):
|
|
_name = 'insurance.type'
|
|
|
|
name = fields.Char(
|
|
string='',
|
|
required=False)
|
|
description = fields.Char(
|
|
string='Description',
|
|
required=False)
|
|
|
|
|
|
class Cars(models.Model):
|
|
_name = 'cars.line'
|
|
|
|
name = fields.Char()
|
|
benefit_id = fields.Many2one('grant.benefit')
|
|
is_driver_family_member = fields.Boolean(string="Is Driver Family Member?", default=True)
|
|
driver_name = fields.Char(string="Driver Name")
|
|
member_id = fields.Many2one('family.member',domain="[('benefit_id','=',benefit_id)]", string="Member")
|
|
car_model = fields.Many2one('benefit.vehicle.model', ondelete='restrict')
|
|
status = fields.Selection(
|
|
string='',
|
|
selection=[('good', 'Good'),
|
|
('bad', 'bad'), ],
|
|
required=False,default='good' ) # TODO
|
|
|
|
purchased_by_association = fields.Boolean(
|
|
string="Purchased by the Association?",
|
|
default=False,
|
|
help="Indicates whether the car was purchased by the association"
|
|
)
|
|
application_form = fields.Many2many('ir.attachment','cars_application_form_rel', 'cars_id','attachment_id',string="Application Form")
|
|
driving_license = fields.Many2many('ir.attachment','cars_driving_license_rel','cars_id','attachment_id',string="Driving License")
|
|
owner_identity = fields.Many2many('ir.attachment','cars_owner_identity_rel','cars_id', 'attachment_id',string="Owner Identity")
|
|
|
|
@api.onchange('is_driver_family_member')
|
|
def _onchange_is_driver_family_member(self):
|
|
for rec in self:
|
|
if rec.is_driver_family_member:
|
|
rec.driver_name = False
|
|
else:
|
|
rec.member_id = False
|
|
|
|
class TrainingType(models.Model):
|
|
_name = 'training.type'
|
|
|
|
name = fields.Char()
|
|
|
|
|
|
class Committees(models.Model):
|
|
_name = 'committees.line'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
|
|
name = fields.Char()
|
|
employee_id = fields.Many2many('hr.employee',domain="[('branch_name','=',branch_id)]", string="Employee")
|
|
type = fields.Selection(
|
|
string='',
|
|
selection=[('male', 'Men'),
|
|
('female', 'women'),
|
|
('both', 'combined'),
|
|
],
|
|
required=False, )
|
|
branch_custom_id = fields.Many2one("branch.settings", string="Branch")
|
|
branch_id = fields.Many2one('hr.department',string='Branch',related='branch_custom_id.branch',store=True)
|
|
active = fields.Boolean('Active', default=True)
|
|
benefit_count = fields.Integer(compute="get_benefit_count")
|
|
mobile = fields.Char(string="Mobile Number")
|
|
|
|
@api.constrains('mobile')
|
|
def _check_mobile(self):
|
|
for rec in self:
|
|
if rec.mobile and not re.match(SAUDI_MOBILE_PATTERN, rec.mobile):
|
|
raise ValidationError(
|
|
_("Please enter a valid Saudi mobile number (example: 05xxxxxxxx).")
|
|
)
|
|
|
|
def get_benefit_count(self):
|
|
for record in self:
|
|
benefit_ids = self.env['grant.benefit'].search([('researcher_id', 'in', record.ids)])
|
|
record.benefit_count = len(benefit_ids)
|
|
|
|
def action_view_benefits(self):
|
|
return {
|
|
'name': _('Benefits'),
|
|
'type': 'ir.actions.act_window',
|
|
'res_model': 'grant.benefit',
|
|
'view_mode': 'tree,form',
|
|
'domain': [('researcher_id', 'in', self.ids)],
|
|
'target': 'current',
|
|
}
|
|
|
|
class ResDistricts(models.Model):
|
|
_name = 'res.districts'
|
|
|
|
name = fields.Char(string="Name")
|
|
meal_card = fields.Boolean(string='Meal Card')
|
|
city_id = fields.Many2one('res.country.city')
|
|
branch_custom_id = fields.Many2one("branch.settings", string="Branch")
|
|
|
|
class VisitsSettings(models.Model):
|
|
_name = 'visits.types'
|
|
|
|
name = fields.Char(string="Name", required=True)
|
|
creation_method = fields.Selection(
|
|
[('manual', 'Manual'),('automatic', 'Automatic')],
|
|
string="Creation Method",
|
|
default='manual',
|
|
required=True,
|
|
help="Whether the visit is entered manually or created automatically"
|
|
)
|
|
recurrence_interval = fields.Integer(
|
|
string="Recurrence Interval",
|
|
default=1,
|
|
help="Determines how often visits are created automatically"
|
|
)
|
|
recurrence_period = fields.Selection([
|
|
('days', 'Days'),
|
|
('weeks', 'Weeks'),
|
|
('months', 'Months')
|
|
], string="Recurrence Period", default='days',
|
|
help="Time unit for recurrence")
|
|
otp_verification = fields.Boolean(
|
|
string="OTP Verification",
|
|
default=False,
|
|
help="Whether this visit requires OTP confirmation from the family"
|
|
)
|
|
otp_validity_minutes = fields.Integer(
|
|
string="OTP Validity (Minutes)",
|
|
default=5,
|
|
help="OTP code validity duration in minutes"
|
|
)
|
|
active = fields.Boolean(
|
|
string="Active",
|
|
default=True
|
|
)
|
|
survey_id = fields.Many2one(
|
|
'survey.survey',
|
|
string="Evaluation Survey"
|
|
)
|
|
|
|
class SurveySetting(models.Model):
|
|
_name = 'survey.setting'
|
|
|
|
survey_url = fields.Char("Survey URL")
|
|
|
|
class SuspendReason(models.Model):
|
|
_name = 'suspend.reason'
|
|
_description = "Suspend - Reason"
|
|
|
|
name = fields.Char(string="Name", required=True)
|
|
is_stop_reason = fields.Boolean(string="Stop Reason",default=False)
|
|
is_reject_reason = fields.Boolean(string="Reject Reason",default=False)
|
|
is_return_reason = fields.Boolean(string="Return Reason",default=False)
|
|
is_resume_reason = fields.Boolean(string="Resume Reason", default=False)
|
|
is_family_return_reason = fields.Boolean(string="Family Return Reason",default=False)
|
|
is_incomplete_visit_reason = fields.Boolean(string="Incomplete Visit Reason",default=False)
|
|
active = fields.Boolean(default=True)
|
|
entity_type = fields.Selection([('family', 'Family'),('member', 'Member')],string='Entity Type')
|
|
allow_service = fields.Boolean(string="Allow Service Use", default=False)
|
|
days_before_final_suspend = fields.Integer(string="Days Before Final Suspension",
|
|
default=0,help="Number of days before the suspension becomes final.")
|
|
suspend_type = fields.Selection(
|
|
selection=[('temporarily_suspend', 'Temporarily Suspended'), ('suspend', 'Suspend')], string="Suspend Type",)
|
|
need_service_manager_approval = fields.Boolean(
|
|
string="Needs Service Manager Approval"
|
|
)
|
|
check_all_members_non_benefit = fields.Boolean(string="Check All Members Non-Benefit",default=False)
|
|
|
|
class ReturnReason(models.Model):
|
|
_name = "return.reason"
|
|
_description = "Return Reasons"
|
|
|
|
name = fields.Char(string="Name", required=True)
|
|
active = fields.Boolean(string="Active", default=True)
|
|
|
|
class BranchSettings(models.Model):
|
|
_name = 'branch.settings'
|
|
_description = "Branch Settings"
|
|
|
|
name = fields.Char(related='branch.name')
|
|
branch = fields.Many2one('hr.department',string='Branch',domain =[('is_branch', '=', True)])
|
|
manager_id = fields.Many2one('hr.employee', related='branch.manager_id')
|
|
operation_manager_id = fields.Many2one('hr.employee', related='branch.operation_manager_id')
|
|
branch_type = fields.Selection(
|
|
selection=[
|
|
('branches', 'Branches'),
|
|
('governorates', 'Governorates')],
|
|
string='Branch Type')
|
|
city_id = fields.Many2one('res.country.city')
|
|
has_employees = fields.Boolean('Has Employees' ,defualt=True)
|
|
replacement_branch_id = fields.Many2one(
|
|
'branch.settings',
|
|
string="Replacement Branch"
|
|
)
|
|
service_producer_id = fields.Many2one('res.partner', string='Service Producer')
|
|
|
|
class RelationSettings(models.Model):
|
|
_name = 'relation.settings'
|
|
_description = "Relation Settings"
|
|
|
|
name = fields.Char(string='name')
|
|
relation_type = fields.Selection(
|
|
[('son', _('Son')), ('daughter', _('Daughter')),('mother', _('Mother')),('replacement_mother', _('Replacement Mother')),('other relation', _('Other Relation'))])
|
|
age_difference = fields.Integer()
|
|
grace_period_days = fields.Integer(
|
|
string="Grace Period After Age Limit (Days)",
|
|
default=0,
|
|
help="Number of days the member remains eligible for benefits after reaching the configured age limit."
|
|
)
|
|
|
|
class LocationSettings(models.Model):
|
|
_name = 'location.settings'
|
|
_description = "Location Settings"
|
|
|
|
name = fields.Char(string='name')
|
|
location_type = fields.Selection([('member', _('Member')), ('mother_location', _('Mother Location'))])
|
|
is_benefit = fields.Boolean(string='Is Benefit?')
|
|
is_far_from_family = fields.Boolean(string='Is Far From Family?')
|
|
replacement_mother_is_benefit = fields.Boolean(string="Replacement Mother Is Benefit?", default=True, )
|
|
|
|
class AttachmentsSettings(models.Model):
|
|
_name = 'attachments.settings'
|
|
_description = "Attachments Settings"
|
|
_order = 'family_appearance_seq,member_appearance_seq,income_appearance_seq asc'
|
|
|
|
name = fields.Char(string='name')
|
|
hobby_id = fields.Many2one('hobbies.settings',string='Hobbies')
|
|
diseases_id = fields.Many2one('diseases.settings',string='Diseases')
|
|
disabilities_id = fields.Many2one('disabilities.settings',string='Disabilities')
|
|
attach_type = fields.Selection(
|
|
[('family_attach', _('Family Attach')), ('member_attach', _('Member Attach')), ('hobbies_attach', _('Hobbies Attach')),
|
|
('diseases_attach', _('Diseases Attach')), ('disabilities_attach', _('Disabilities Attach')), ('income_attach', _('Income Attach')), ('expense_attach', _('Expense Attach')), ('exams_attach', _('Exams Attach'))])
|
|
is_required = fields.Boolean(string='Is Required?')
|
|
is_default = fields.Boolean(string='Is Default?')
|
|
show_in_portal = fields.Boolean(default=True)
|
|
family_appearance_seq = fields.Integer(string='Appearance Sequence')
|
|
member_appearance_seq = fields.Integer(string='Appearance Sequence')
|
|
income_appearance_seq = fields.Integer(string='Appearance Sequence')
|
|
is_mother_salary = fields.Boolean(string="Is Mother Salary", default=False)
|
|
parent_id = fields.Many2one('attachments.settings',string='Parent')
|
|
child_ids = fields.One2many('attachments.settings','parent_id',string='Children')
|
|
|
|
@api.constrains('parent_id')
|
|
def _check_no_recursive_parent(self):
|
|
for rec in self:
|
|
parent = rec.parent_id
|
|
while parent:
|
|
if parent == rec:
|
|
raise ValidationError(
|
|
"Recursive hierarchy is not allowed."
|
|
)
|
|
parent = parent.parent_id
|
|
|
|
class EducationIlliterateReason(models.Model):
|
|
_name = 'education.illiterate.reason'
|
|
_description = "Education Illiterate Reason"
|
|
|
|
name = fields.Char(string='name')
|
|
|
|
|
|
class EducationDelayReason(models.Model):
|
|
_name = 'education.delay.reason'
|
|
_description = "Education Delay Reason"
|
|
|
|
name = fields.Char(string='Name', required=True)
|
|
|
|
class IncomeType(models.Model):
|
|
_name = 'income.type'
|
|
_description = "Income Type"
|
|
|
|
name = fields.Char(string='name')
|
|
|
|
class LoanGiver(models.Model):
|
|
_name = 'loan.giver'
|
|
_description = "LoanGiver"
|
|
|
|
name = fields.Char(string='name')
|
|
|
|
class LoanReason(models.Model):
|
|
_name = 'loan.reason'
|
|
_description = "Loan Reason"
|
|
|
|
name = fields.Char(string='name')
|
|
|
|
class HobbiesSettings(models.Model):
|
|
_name = 'hobbies.settings'
|
|
|
|
name = fields.Char(string="Name")
|
|
|
|
class DiseasesSettings(models.Model):
|
|
_name = 'diseases.settings'
|
|
|
|
name = fields.Char(string="Name")
|
|
|
|
class DisabilitiesSettings(models.Model):
|
|
_name = 'disabilities.settings'
|
|
|
|
name = fields.Char(string="Name")
|
|
|
|
class ExceptionReason(models.Model):
|
|
_name = 'exception.reason'
|
|
|
|
name = fields.Char(string="Name")
|
|
|
|
class MaritalStatus(models.Model):
|
|
_name = 'marital.status'
|
|
|
|
name = fields.Char(string="Name")
|
|
is_benefit = fields.Boolean(string='Is Benefit?')
|
|
is_dead = fields.Boolean(string='Is Dead?')
|
|
replacement_mother_is_benefit = fields.Boolean(string="Replacement Mother Is Benefit?",default=True,)
|
|
|
|
class AgeCategory(models.Model):
|
|
_name = 'age.category'
|
|
|
|
min_age = fields.Integer(string="From")
|
|
max_age = fields.Integer(string="To")
|
|
name = fields.Char(string="Name", compute="_compute_name", store=True)
|
|
|
|
@api.depends('min_age', 'max_age')
|
|
def _compute_name(self):
|
|
for record in self:
|
|
if record.min_age is not None and record.max_age is not None:
|
|
record.name = f"[{record.min_age}:{record.max_age}]"
|
|
else:
|
|
record.name = ""
|
|
|
|
class ComplaintsCategory(models.Model):
|
|
_name = 'complaints.category'
|
|
|
|
def _get_default_color(self):
|
|
return randint(1, 11)
|
|
|
|
name = fields.Char('Category Name', required=True, translate=True)
|
|
color = fields.Integer('Color', default=_get_default_color)
|
|
|
|
|
|
class ServiceAttachmentsSettings(models.Model):
|
|
_name = 'service.attachments.settings'
|
|
_description = "Service Attachments Settings"
|
|
|
|
name = fields.Char(string='name')
|
|
service_attach = fields.Many2many('ir.attachment','rel_service_attachments', 'service_id', 'attach_id',string="Attachment")
|
|
service_type = fields.Selection(
|
|
[('rent', 'Rent'), ('home_restoration', 'Home Restoration'), ('alternative_housing', 'Alternative Housing'),
|
|
('home_maintenance', 'Home Maintenance'), ('complete_building_house', 'Complete Building House'), ('electrical_devices', 'Electrical Devices'),
|
|
('home_furnishing', 'Home furnishing')
|
|
, ('electricity_bill', 'Electricity bill'), ('water_bill', 'Water bill'), ('buy_car', 'Buy Car'),
|
|
('recruiting_driver', 'Recruiting Driver')
|
|
, ('transportation_insurance', 'Transportation Insurance'), ('debits', 'Debits'),
|
|
('health_care', 'Health Care'),
|
|
('providing_medicines_medical_devices_and_needs_the_disabled',
|
|
'Providing Medicines Medical Devices And Needs The Disabled'),
|
|
('recruiting_domestic_worker_or_nurse', 'Recruiting a domestic worker or nurse'), ('marriage', 'Marriage'),
|
|
('eid_gift', 'Eid gift'),
|
|
('winter_clothing', 'Winter clothing'), ('ramadan_basket', 'Ramadan basket'),
|
|
('natural_disasters', 'Natural disasters'), ('legal_arguments', 'Legal arguments')],string='Service Type',related="service_id.service_type")
|
|
service_id = fields.Many2one('services.settings',string='Service')
|
|
service_request_id = fields.Many2one('service.request',string='Service Request')
|
|
previous_service_attachment_settings_id = fields.Many2one('service.attachments.settings', readonly=True)
|
|
notes = fields.Text(string='Notes')
|
|
state = fields.Selection(selection=[
|
|
('draft', 'Draft'),
|
|
('waiting_family', 'Waiting Family'),
|
|
('researcher', 'Researcher'),
|
|
('waiting_approve', 'Waiting for Operation Manager'),
|
|
('first_approve', 'Waiting for Branch Manager'),
|
|
('family_services_manager', 'Waiting Family Services Manager'),
|
|
('legal_department', 'Waiting Legal Department'),
|
|
('projects_department', 'Waiting Projects Department'),
|
|
('gm_assistant', 'Waiting Assistant General Manager'),
|
|
('accounting_approve', 'Accounting Approve'),
|
|
('return_to_bank', 'Return to Bank'),
|
|
('approval_of_beneficiary_services', 'Approval of beneficiary services'),
|
|
('send_request_to_supplier', 'Send Request To Supplier'),
|
|
('family_received_device', 'Family Received Device'),
|
|
('refused', 'Refused')
|
|
], string='State', default='waiting_family')
|
|
|
|
class HomeMaintenanceItems(models.Model):
|
|
_name = 'home.maintenance.items'
|
|
|
|
maintenance_items_id = fields.Many2one('home.maintenance.lines', string="Maintenance Items")
|
|
service_request_id = fields.Many2one('service.request',string='Service Request')
|
|
|
|
class HomeFurnishingItems(models.Model):
|
|
_name = 'home.furnishing.items'
|
|
|
|
home_furnishing_items = fields.Many2one('home.furnishing.lines', string='Furnishing Items')
|
|
furnishing_cost = fields.Float(string='Furnishing Cost')
|
|
price_first = fields.Float(string='Price First')
|
|
price_first_attach = fields.Many2many('ir.attachment','rel_first_price_attachments', 'furnishing_id', 'attach_id',string="First Price Attachment")
|
|
price_second = fields.Float(string='Price Second')
|
|
price_second_attach = fields.Many2many('ir.attachment','rel_second_price_attachments', 'furnishing_id', 'attach_id',string="Second Price Attachment")
|
|
service_request_id = fields.Many2one('service.request',string='Service Request')
|
|
|
|
class ElectricalDeviceLine(models.Model):
|
|
_name = 'electrical.device.line'
|
|
_description = 'Electrical Device Line'
|
|
|
|
service_request_id = fields.Many2one('service.request',string='Service Request',ondelete='cascade',)
|
|
device_id = fields.Many2one('electrical.devices',string='Device',compute='_compute_device_id',store=True)
|
|
product_id = fields.Many2one('product.product',string='Product',required=True,)
|
|
quantity = fields.Integer(string='Quantity',required=True,default=1)
|
|
unit_price = fields.Float( string='Unit Price',compute='_compute_unit_price',store=True)
|
|
subtotal = fields.Float(string='Subtotal',compute='_compute_subtotal',store=True)
|
|
|
|
@api.depends('device_id')
|
|
def _compute_unit_price(self):
|
|
for line in self:
|
|
if line.device_id:
|
|
line.unit_price = line.product_id.standard_price
|
|
else:
|
|
line.unit_price = 0.0
|
|
|
|
@api.depends('quantity', 'unit_price')
|
|
def _compute_subtotal(self):
|
|
for line in self:
|
|
line.subtotal = line.quantity * line.unit_price
|
|
|
|
@api.depends('product_id', 'service_request_id.benefit_member_count', 'service_request_id.service_cat')
|
|
def _compute_device_id(self):
|
|
for line in self:
|
|
if not line.product_id or not line.service_request_id or not line.service_request_id.service_cat:
|
|
line.device_id = False
|
|
continue
|
|
|
|
member_count = line.service_request_id.benefit_member_count or 0
|
|
|
|
matching = line.service_request_id.service_cat.electrical_devices_lines.filtered(
|
|
lambda d: line.product_id in d.product_ids
|
|
and (d.min_count_member or 0) <= member_count <= (d.max_count_member or 999999)
|
|
)
|
|
|
|
if matching:
|
|
line.device_id = matching[0]
|
|
else:
|
|
line.device_id = False
|
|
|
|
class PropertyTypeSettings(models.Model):
|
|
_name = 'property.type.settings'
|
|
_description = 'Property Type Settings'
|
|
_order = 'name'
|
|
|
|
name = fields.Char(string="Name", required=True)
|
|
type = fields.Selection([
|
|
('ownership', 'Ownership'),
|
|
('rent', 'Rent')
|
|
], string="Property Type", required=True)
|
|
is_shared = fields.Boolean(string="Shared", default=False)
|
|
active = fields.Boolean(string="Active", default=True)
|
|
unavailable_service_ids = fields.Many2many(
|
|
'services.settings',
|
|
string="Unavailable Services",
|
|
help="Services that are not available for families or members with this property type"
|
|
)
|
|
|
|
class RentContract(models.Model):
|
|
_name = 'rent.contract'
|
|
_description = 'Rent Contract'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
_order = 'create_date desc, id desc'
|
|
|
|
name = fields.Char(string='Contract Number',required=True,copy=False,tracking=True)
|
|
family_id = fields.Many2one('grant.benefit',string='Family',required=True,ondelete='cascade')
|
|
member_id = fields.Many2one('family.member',string='Member (Tenant)',
|
|
domain="""[
|
|
('benefit_id', '=', family_id),
|
|
('education_status', '=', 'educated'),
|
|
('member_education_status_ids', '!=', False),
|
|
('member_education_status_ids.case_study', '=', 'continuous')
|
|
]"""
|
|
)
|
|
contract_type = fields.Selection([
|
|
('fixed', 'Fixed Term'),
|
|
('unlimited', 'Indefinite'),
|
|
], string='Contract Type', required=True, default='fixed', tracking=True)
|
|
start_date = fields.Date(string='Start Date', required=True)
|
|
end_date = fields.Date(string='End Date')
|
|
payment_type = fields.Selection([
|
|
('1', 'Yearly'),
|
|
('2', 'Half-yearly'),
|
|
('4', 'Quarterly'),
|
|
('12', 'Monthly'),
|
|
], string='Payment Type', required=True, default='2')
|
|
rent_amount = fields.Float(string='Rent Amount', required=True)
|
|
contract_attachment = fields.Many2many(
|
|
'ir.attachment', 'rent_contract_attachment_rel',
|
|
'contract_id', 'attachment_id',
|
|
string='Contract Attachment'
|
|
)
|
|
electricity_bill_attachment = fields.Many2many(
|
|
'ir.attachment', 'rent_electricity_bill_rel',
|
|
'contract_id', 'attachment_id',
|
|
string='Electricity Bill Attachment'
|
|
)
|
|
state = fields.Selection([
|
|
('active', 'Active'),
|
|
('expired', 'Expired'),
|
|
], string='Status', default='active', tracking=True)
|
|
landlord_type = fields.Selection([
|
|
('family', 'Family'),
|
|
('member', 'Member / Student'),
|
|
], string='Landlord Type', default='family', required=True)
|
|
|
|
@api.onchange('end_date', 'start_date')
|
|
def _onchange_contract_dates(self):
|
|
if self.end_date and self.start_date and self.end_date < self.start_date:
|
|
raise ValidationError(_("End Date cannot be before Start Date."))
|
|
|
|
@api.onchange('landlord_type')
|
|
def _onchange_landlord_type(self):
|
|
for rec in self:
|
|
if rec.landlord_type == 'family':
|
|
rec.member_id = False |